1use crate::core::exec::input::{InputBuf, InputSlice};
7use crate::core::exec::output::*;
8use crate::core::exec::{
9 parser::{PResult, Parser},
10 serializer::{ByteLen, PreSerializeError, Prepare, Serializer},
11 ParseError,
12};
13use crate::{
14 combinators::{
15 mapped::spec::FnSpecMapper,
16 uints::{exec::u32_to_be_bytes, spec::*},
17 Mapped, Refined, Tail,
18 },
19 core::{proof::*, spec::*},
20};
21#[cfg(feature = "alloc")]
22use alloc::string::String;
23use vstd::prelude::*;
24#[cfg(feature = "alloc")]
25use vstd::string::StrSliceExecFns;
26use OutputBuf;
27
28verus! {
29
30#[cfg(feature = "alloc")]
31pub type UniversalString = String;
32
33pub type UniversalStringSpec = Seq<char>;
34
35pub open spec fn universal_code_point(bytes: Seq<u8>, i: int) -> u32
36 recommends
37 0 <= 4 * i,
38 4 * i + 3 < bytes.len(),
39{
40 u32_be_from_bytes([bytes[4 * i], bytes[4 * i + 1], bytes[4 * i + 2], bytes[4 * i + 3]])
41}
42
43pub open spec fn is_valid_universal_string(bytes: Seq<u8>) -> bool {
45 &&& bytes.len() % 4 == 0
46 &&& forall|i: int|
47 0 <= i < bytes.len() / 4 ==> vstd::utf8::is_scalar(
48 #[trigger] universal_code_point(bytes, i),
49 )
50}
51
52pub open spec fn decode_universal_string(bytes: Seq<u8>) -> Seq<char> {
54 Seq::new(bytes.len() / 4, |i: int| universal_code_point(bytes, i) as char)
55}
56
57pub open spec fn encode_universal_string(chars: Seq<char>) -> Seq<u8> {
59 Seq::new(chars.len() * 4, |i: int| u32_be_to_bytes(chars[i / 4] as u32)[i % 4])
60}
61
62proof fn lemma_scalar_char_cast(u: u32)
63 requires
64 vstd::utf8::is_scalar(u),
65 ensures
66 (u as char) as u32 == u,
67{
68}
69
70proof fn lemma_encoded_universal_code_point(chars: Seq<char>, i: int)
71 requires
72 0 <= i < chars.len(),
73 ensures
74 universal_code_point(encode_universal_string(chars), i) == chars[i] as u32,
75{
76 let c = chars[i];
77 let word = u32_be_to_bytes(c as u32);
78 lemma_u32_be_value_roundtrip(c as u32);
79 assert(encode_universal_string(chars)[4 * i] == word[0]);
80 assert(encode_universal_string(chars)[4 * i + 1] == word[1]);
81 assert(encode_universal_string(chars)[4 * i + 2] == word[2]);
82 assert(encode_universal_string(chars)[4 * i + 3] == word[3]);
83}
84
85proof fn lemma_decoded_universal_code_point(bytes: Seq<u8>, i: int)
86 requires
87 is_valid_universal_string(bytes),
88 0 <= i < bytes.len() / 4,
89 ensures
90 u32_be_to_bytes(decode_universal_string(bytes)[i] as u32) == [
91 bytes[4 * i],
92 bytes[4 * i + 1],
93 bytes[4 * i + 2],
94 bytes[4 * i + 3],
95 ],
96{
97 let word = [bytes[4 * i], bytes[4 * i + 1], bytes[4 * i + 2], bytes[4 * i + 3]];
98 let code = u32_be_from_bytes(word);
99 assert(code == universal_code_point(bytes, i));
100 assert(vstd::utf8::is_scalar(code));
101 lemma_scalar_char_cast(code);
102 lemma_u32_be_bytes_roundtrip(word);
103}
104
105pub proof fn lemma_encode_universal_string_valid(chars: Seq<char>)
106 ensures
107 is_valid_universal_string(encode_universal_string(chars)),
108{
109 let bytes = encode_universal_string(chars);
110 assert(bytes.len() % 4 == 0);
111 assert forall|i: int| 0 <= i < bytes.len() / 4 implies vstd::utf8::is_scalar(
112 #[trigger] universal_code_point(bytes, i),
113 ) by {
114 vstd::utf8::char_is_scalar(chars[i]);
115 lemma_encoded_universal_code_point(chars, i);
116 }
117}
118
119pub proof fn lemma_decode_encode_universal_string(chars: Seq<char>)
120 ensures
121 decode_universal_string(encode_universal_string(chars)) == chars,
122{
123 let bytes = encode_universal_string(chars);
124 assert(decode_universal_string(bytes).len() == chars.len());
125 assert forall|i: int| 0 <= i < chars.len() implies #[trigger] decode_universal_string(bytes)[i]
126 == chars[i] by {
127 lemma_encoded_universal_code_point(chars, i);
128 vstd::utf8::char_u32_cast(chars[i], universal_code_point(bytes, i));
129 }
130}
131
132pub proof fn lemma_encode_decode_universal_string(bytes: Seq<u8>)
133 requires
134 is_valid_universal_string(bytes),
135 ensures
136 encode_universal_string(decode_universal_string(bytes)) == bytes,
137{
138 let chars = decode_universal_string(bytes);
139 assert(encode_universal_string(chars).len() == bytes.len());
140 assert forall|i: int| 0 <= i < bytes.len() implies #[trigger] encode_universal_string(chars)[i]
141 == bytes[i] by {
142 lemma_decoded_universal_code_point(bytes, i / 4);
143 }
144}
145
146type UniversalStringInnerFmt = Mapped<
147 Refined<Tail, PredFnSpec<Seq<u8>>>,
148 FnSpecMapper<Seq<u8>, Seq<char>>,
149>;
150
151pub open spec fn universalstring_fmt() -> UniversalStringInnerFmt {
152 Mapped {
153 inner: Refined(Tail, |bytes: Seq<u8>| is_valid_universal_string(bytes)),
154 mapper: (
155 |bytes: Seq<u8>| decode_universal_string(bytes),
156 |chars: Seq<char>| encode_universal_string(chars),
157 ),
158 }
159}
160
161proof fn lemma_universalstring_fmt_sound_nonmal_inv()
162 ensures
163 universalstring_fmt().sound_inv(),
164 universalstring_fmt().nonmal_inv(),
165{
166 assert forall|bytes: Seq<u8>| #[trigger]
167 is_valid_universal_string(bytes) implies encode_universal_string(
168 decode_universal_string(bytes),
169 ) == bytes by {
170 lemma_encode_decode_universal_string(bytes);
171 }
172}
173
174mod derived_specs {
175 use super::*;
176
177 impl SpecParser for super::super::UniversalStringFmt {
178 type PVal = Seq<char>;
179
180 open spec fn spec_parse(&self, ibuf: Seq<u8>) -> Option<(int, Self::PVal)> {
181 universalstring_fmt().spec_parse(ibuf)
182 }
183 }
184
185 impl Consistency for super::super::UniversalStringFmt {
186 type Val = Seq<char>;
187
188 open spec fn consistent(&self, value: Self::Val) -> bool {
189 universalstring_fmt().consistent(value)
190 }
191 }
192
193 impl SpecSerializerDps for super::super::UniversalStringFmt {
194 type SValue = Seq<char>;
195
196 open spec fn spec_serialize_dps(&self, value: Self::SValue, obuf: Seq<u8>) -> Seq<u8> {
197 universalstring_fmt().spec_serialize_dps(value, obuf)
198 }
199 }
200
201 impl SpecSerializer for super::super::UniversalStringFmt {
202 type SVal = Seq<char>;
203
204 open spec fn spec_serialize(&self, value: Self::SVal) -> Seq<u8> {
205 universalstring_fmt().spec_serialize(value)
206 }
207 }
208
209 impl SpecByteLen for super::super::UniversalStringFmt {
210 type T = Seq<char>;
211
212 open spec fn byte_len(&self, value: Self::T) -> nat {
213 universalstring_fmt().byte_len(value)
214 }
215 }
216
217}
218
219pub(crate) proof fn lemma_universal_string_fmt_serialization(value: Seq<char>)
220 ensures
221 super::UniversalStringFmt.spec_serialize(value) == encode_universal_string(value),
222 super::UniversalStringFmt.byte_len(value) == value.len() * 4,
223{
224}
225
226mod derived_proofs {
227 use super::*;
228
229 impl SafeParser for super::super::UniversalStringFmt {
230 proof fn lemma_parse_safe(&self, ibuf: Seq<u8>) {
231 universalstring_fmt().lemma_parse_safe(ibuf);
232 }
233 }
234
235 impl Productive for super::super::UniversalStringFmt {
236 open spec fn productive_inv(&self) -> bool {
237 false
238 }
239
240 proof fn lemma_productive(&self, _input: Seq<u8>) {
241 }
242 }
243
244 impl SoundParser for super::super::UniversalStringFmt {
245 proof fn lemma_parse_sound_consumption(&self, ibuf: Seq<u8>) {
246 lemma_universalstring_fmt_sound_nonmal_inv();
247 universalstring_fmt().lemma_parse_sound_consumption(ibuf);
248 }
249
250 proof fn lemma_parse_sound_value(&self, ibuf: Seq<u8>) {
251 lemma_universalstring_fmt_sound_nonmal_inv();
252 universalstring_fmt().lemma_parse_sound_value(ibuf);
253 }
254 }
255
256 impl GoodSerializer for super::super::UniversalStringFmt {
257 proof fn lemma_serialize_len(&self, value: Self::SVal) {
258 universalstring_fmt().lemma_serialize_len(value);
259 }
260 }
261
262 impl SPRoundTripDps for super::super::UniversalStringFmt {
263 proof fn theorem_serialize_dps_parse_roundtrip(&self, value: Self::T, obuf: Seq<u8>) {
264 lemma_encode_universal_string_valid(value);
265 lemma_decode_encode_universal_string(value);
266 let bytes = encode_universal_string(value);
267 let inner = Refined(Tail, |bytes: Seq<u8>| is_valid_universal_string(bytes));
268 inner.theorem_serialize_dps_parse_roundtrip(bytes, obuf);
269 }
270 }
271
272 impl NonMalleable for super::super::UniversalStringFmt {
273 proof fn lemma_parse_non_malleable(&self, buf1: Seq<u8>, buf2: Seq<u8>) {
274 lemma_universalstring_fmt_sound_nonmal_inv();
275 universalstring_fmt().lemma_parse_non_malleable(buf1, buf2);
276 }
277 }
278
279 impl EquivSerializers for super::super::UniversalStringFmt {
280 proof fn lemma_serialize_equiv_on_empty(&self, value: Self::SVal) {
281 universalstring_fmt().lemma_serialize_equiv_on_empty(value);
282 }
283 }
284
285}
286
287#[verifier::external_body]
289pub fn check_valid_universal_string(bytes: &[u8]) -> (valid: bool)
290 ensures
291 valid == is_valid_universal_string(bytes.deep_view()),
292{
293 if bytes.len() % 4 != 0 {
294 return false;
295 }
296 bytes.chunks_exact(4).map(|word| u32::from_be_bytes([word[0], word[1], word[2], word[3]])).all(
297 |code| char::from_u32(code).is_some(),
298 )
299}
300
301#[cfg(feature = "alloc")]
302#[verifier::external_body]
303pub(crate) fn decode_universal_string_owned(bytes: &[u8]) -> (value: String)
304 requires
305 is_valid_universal_string(bytes.deep_view()),
306 ensures
307 value.deep_view() == decode_universal_string(bytes.deep_view()),
308{
309 bytes.chunks_exact(4).map(
310 |word|
311 unsafe {
312 char::from_u32_unchecked(u32::from_be_bytes([word[0], word[1], word[2], word[3]]))
313 },
314 ).collect()
315}
316
317#[cfg(feature = "alloc")]
318impl<'i> Parser<&'i [u8]> for super::UniversalStringFmt {
319 type PT = UniversalString;
320
321 fn parse(&self, ibuf: &&'i [u8]) -> PResult<Self::PT> {
322 let (n, bytes) = Tail.parse(ibuf)?;
323 if !check_valid_universal_string(bytes) {
324 Err(ParseError::custom("Invalid UniversalString"))
325 } else {
326 Ok((n, decode_universal_string_owned(bytes)))
327 }
328 }
329}
330
331#[cfg(feature = "alloc")]
332impl<Output: OutputBuf> Serializer<Output, UniversalString> for super::UniversalStringFmt {
333 #[verifier::loop_isolation(false)]
334 fn serialize_into(&self, value: &UniversalString, obuf: &mut Output) {
335 broadcast use crate::core::exec::output::outbuf_lemmas;
336
337 proof {
338 lemma_encode_universal_string_valid(value.deep_view());
339 }
340 let value = value.as_str();
341
342 let ghost initial = obuf@;
343 let len = value.unicode_len();
344 for i in 0..len
345 invariant
346 obuf@ == initial + encode_universal_string(value.deep_view().take(i as int)),
347 forall|n| old(obuf).fits(4 * i as nat + n) <==> obuf.fits(n),
348 old(obuf).same_destination(obuf),
349 {
350 proof {
351 old(obuf).lemma_fits_mono(4 * i as nat + 4, 4 * len as nat);
352 }
353 let c = value.get_char(i);
354 let word = u32_to_be_bytes(c as u32);
355 obuf.write_bytes(&word);
356 }
357 }
358}
359
360#[cfg(feature = "alloc")]
361impl Prepare<UniversalString> for super::UniversalStringFmt {
362 fn prepare(&self, value: &UniversalString) -> Result<usize, PreSerializeError> {
363 proof {
364 lemma_encode_universal_string_valid(value.deep_view());
365 }
366 value.as_str().unicode_len().checked_mul(4).ok_or(PreSerializeError::length_too_large())
367 }
368}
369
370#[cfg(feature = "alloc")]
371impl ByteLen<UniversalString> for super::UniversalStringFmt {
372 fn length(&self, value: &UniversalString) -> usize {
373 value.as_str().unicode_len() * 4
374 }
375}
376
377}