1use crate::core::exec::input::{InputBuf, InputSlice};
3use crate::core::exec::output::*;
4use crate::core::exec::{
5 parser::{PResult, Parser},
6 serializer::{ByteLen, PreSerializeError, Prepare, Serializer},
7 ParseError,
8};
9use crate::{
10 combinators::{
11 mapped::spec::FnSpecMapper,
12 uints::{
13 exec::{u16_from_be_bytes, u16_to_be_bytes},
14 spec::*,
15 },
16 Mapped, Refined, Tail,
17 },
18 core::{proof::*, spec::*},
19};
20#[cfg(feature = "alloc")]
21use alloc::string::String;
22use vstd::prelude::*;
23#[cfg(verus_only)]
24use vstd::std_specs::iter::IteratorSpec;
25use vstd::string::StrSliceExecFns;
26use OutputBuf;
27
28verus! {
29
30#[cfg(feature = "alloc")]
34pub struct BmpString {
35 inner: String,
36}
37
38#[verifier::ext_equal]
39pub struct BmpStringSpec {
40 pub inner: Seq<char>,
41}
42
43#[cfg(feature = "alloc")]
44impl DeepView for BmpString {
45 type V = BmpStringSpec;
46
47 closed spec fn deep_view(&self) -> Self::V {
48 BmpStringSpec { inner: self.inner.deep_view() }
49 }
50}
51
52pub open spec fn is_bmp_char(c: char) -> bool {
53 (c as u32) <= 0xffff
54}
55
56pub open spec fn is_valid_bmp_chars(chars: Seq<char>) -> bool {
57 forall|i: int| 0 <= i < chars.len() ==> is_bmp_char(#[trigger] chars[i])
58}
59
60impl BmpStringSpec {
61 pub open spec fn wf(&self) -> bool {
62 is_valid_bmp_chars(self.inner)
63 }
64}
65
66#[cfg(feature = "alloc")]
67impl BmpString {
68 #[verifier::type_invariant]
69 spec fn wf(&self) -> bool {
70 self.deep_view().wf()
71 }
72
73 pub fn new(inner: String) -> (res: Self)
74 requires
75 is_valid_bmp_chars(inner.deep_view()),
76 ensures
77 res.deep_view() == (BmpStringSpec { inner: inner.deep_view() }),
78 {
79 Self { inner }
80 }
81
82 pub fn inner(&self) -> (res: &str)
83 ensures
84 res.deep_view() == self.deep_view().inner,
85 {
86 self.inner.as_str()
87 }
88}
89
90pub open spec fn bmp_code_unit(bytes: Seq<u8>, i: int) -> u32
91 recommends
92 0 <= 2 * i,
93 2 * i + 1 < bytes.len(),
94{
95 u16_be_from_bytes([bytes[2 * i], bytes[2 * i + 1]]) as u32
96}
97
98pub open spec fn is_valid_bmp_string(bytes: Seq<u8>) -> bool {
100 &&& bytes.len() % 2 == 0
101 &&& forall|i: int|
102 0 <= i < bytes.len() / 2 ==> vstd::utf8::is_scalar(#[trigger] bmp_code_unit(bytes, i))
103}
104
105pub open spec fn decode_bmp_string(bytes: Seq<u8>) -> Seq<char> {
107 Seq::new(bytes.len() / 2, |i: int| bmp_code_unit(bytes, i) as char)
108}
109
110pub open spec fn encode_bmp_string(chars: Seq<char>) -> Seq<u8> {
112 Seq::new(chars.len() * 2, |i: int| u16_be_to_bytes(chars[i / 2] as u16)[i % 2])
113}
114
115proof fn lemma_scalar_char_cast(u: u32)
116 requires
117 vstd::utf8::is_scalar(u),
118 ensures
119 (u as char) as u32 == u,
120{
121}
122
123proof fn lemma_bmp_char_u16_cast(c: char)
124 requires
125 is_bmp_char(c),
126 ensures
127 (c as u16) as u32 == c as u32,
128{
129}
130
131proof fn lemma_encoded_bmp_code_unit(chars: Seq<char>, i: int)
132 requires
133 is_valid_bmp_chars(chars),
134 0 <= i < chars.len(),
135 ensures
136 bmp_code_unit(encode_bmp_string(chars), i) == chars[i] as u32,
137{
138 let c = chars[i];
139 let pair = u16_be_to_bytes(c as u16);
140 lemma_bmp_char_u16_cast(c);
141 lemma_u16_be_value_roundtrip(c as u16);
142 assert(encode_bmp_string(chars)[2 * i] == pair[0]);
143 assert(encode_bmp_string(chars)[2 * i + 1] == pair[1]);
144}
145
146proof fn lemma_decoded_bmp_code_unit(bytes: Seq<u8>, i: int)
147 requires
148 is_valid_bmp_string(bytes),
149 0 <= i < bytes.len() / 2,
150 ensures
151 is_bmp_char(decode_bmp_string(bytes)[i]),
152 u16_be_to_bytes(decode_bmp_string(bytes)[i] as u16) == [bytes[2 * i], bytes[2 * i + 1]],
153{
154 let unit = bmp_code_unit(bytes, i);
155 let pair = [bytes[2 * i], bytes[2 * i + 1]];
156 let code = u16_be_from_bytes(pair);
157 assert(vstd::utf8::is_scalar(unit));
158 lemma_scalar_char_cast(unit);
159 lemma_u16_be_bytes_roundtrip(pair);
160 lemma_bmp_char_u16_cast(unit as char);
161}
162
163pub proof fn lemma_encode_bmp_string_valid(chars: Seq<char>)
164 requires
165 is_valid_bmp_chars(chars),
166 ensures
167 is_valid_bmp_string(encode_bmp_string(chars)),
168{
169 let bytes = encode_bmp_string(chars);
170 assert(bytes.len() % 2 == 0);
171 assert forall|i: int| 0 <= i < bytes.len() / 2 implies vstd::utf8::is_scalar(
172 #[trigger] bmp_code_unit(bytes, i),
173 ) by {
174 let c = chars[i];
175 vstd::utf8::char_is_scalar(c);
176 lemma_encoded_bmp_code_unit(chars, i);
177 }
178}
179
180pub proof fn lemma_decode_encode_bmp_string(chars: Seq<char>)
181 requires
182 is_valid_bmp_chars(chars),
183 ensures
184 decode_bmp_string(encode_bmp_string(chars)) == chars,
185{
186 let bytes = encode_bmp_string(chars);
187 assert(decode_bmp_string(bytes).len() == chars.len());
188 assert forall|i: int| 0 <= i < chars.len() implies #[trigger] decode_bmp_string(bytes)[i]
189 == chars[i] by {
190 lemma_encoded_bmp_code_unit(chars, i);
191 vstd::utf8::char_u32_cast(chars[i], bmp_code_unit(bytes, i));
192 }
193}
194
195pub proof fn lemma_encode_decode_bmp_string(bytes: Seq<u8>)
196 requires
197 is_valid_bmp_string(bytes),
198 ensures
199 encode_bmp_string(decode_bmp_string(bytes)) == bytes,
200{
201 let chars = decode_bmp_string(bytes);
202 assert(encode_bmp_string(chars).len() == bytes.len());
203 assert forall|i: int| 0 <= i < bytes.len() implies #[trigger] encode_bmp_string(chars)[i]
204 == bytes[i] by {
205 let unit_index = i / 2;
206 lemma_decoded_bmp_code_unit(bytes, unit_index);
207 }
208}
209
210pub proof fn lemma_decoded_bmp_string_valid(bytes: Seq<u8>)
211 requires
212 is_valid_bmp_string(bytes),
213 ensures
214 is_valid_bmp_chars(decode_bmp_string(bytes)),
215{
216 assert forall|i: int| 0 <= i < decode_bmp_string(bytes).len() implies is_bmp_char(
217 #[trigger] decode_bmp_string(bytes)[i],
218 ) by {
219 lemma_decoded_bmp_code_unit(bytes, i);
220 }
221}
222
223type BmpStringInnerFmt = Mapped<
224 Refined<Tail, PredFnSpec<Seq<u8>>>,
225 FnSpecMapper<Seq<u8>, BmpStringSpec>,
226>;
227
228pub open spec fn bmpstring_fmt() -> BmpStringInnerFmt {
229 Mapped {
230 inner: Refined(Tail, |bytes: Seq<u8>| is_valid_bmp_string(bytes)),
231 mapper: (
232 |bytes: Seq<u8>| BmpStringSpec { inner: decode_bmp_string(bytes) },
233 |s: BmpStringSpec| encode_bmp_string(s.inner),
234 ),
235 }
236}
237
238proof fn lemma_bmpstring_fmt_sound_nonmal_inv()
239 ensures
240 bmpstring_fmt().sound_inv(),
241 bmpstring_fmt().nonmal_inv(),
242{
243 assert forall|bytes: Seq<u8>| #[trigger] is_valid_bmp_string(bytes) implies encode_bmp_string(
244 decode_bmp_string(bytes),
245 ) == bytes by {
246 lemma_encode_decode_bmp_string(bytes);
247 }
248}
249
250mod derived_specs {
251 use super::*;
252
253 impl SpecParser for super::super::BmpStringFmt {
254 type PVal = BmpStringSpec;
255
256 open spec fn spec_parse(&self, ibuf: Seq<u8>) -> Option<(int, Self::PVal)> {
257 bmpstring_fmt().spec_parse(ibuf)
258 }
259 }
260
261 impl Consistency for super::super::BmpStringFmt {
262 type Val = BmpStringSpec;
263
264 open spec fn consistent(&self, v: Self::Val) -> bool {
265 bmpstring_fmt().consistent(v) && v.wf()
266 }
267 }
268
269 impl SpecSerializerDps for super::super::BmpStringFmt {
270 type SValue = BmpStringSpec;
271
272 open spec fn spec_serialize_dps(&self, v: Self::SValue, obuf: Seq<u8>) -> Seq<u8> {
273 bmpstring_fmt().spec_serialize_dps(v, obuf)
274 }
275 }
276
277 impl SpecSerializer for super::super::BmpStringFmt {
278 type SVal = BmpStringSpec;
279
280 open spec fn spec_serialize(&self, v: Self::SVal) -> Seq<u8> {
281 bmpstring_fmt().spec_serialize(v)
282 }
283 }
284
285 impl SpecByteLen for super::super::BmpStringFmt {
286 type T = BmpStringSpec;
287
288 open spec fn byte_len(&self, v: Self::T) -> nat {
289 bmpstring_fmt().byte_len(v)
290 }
291 }
292
293}
294
295pub(crate) proof fn lemma_bmp_string_fmt_serialization(value: BmpStringSpec)
296 ensures
297 super::BmpStringFmt.spec_serialize(value) == encode_bmp_string(value.inner),
298 super::BmpStringFmt.byte_len(value) == value.inner.len() * 2,
299{
300}
301
302mod derived_proofs {
303 use super::*;
304
305 impl SafeParser for super::super::BmpStringFmt {
306 proof fn lemma_parse_safe(&self, ibuf: Seq<u8>) {
307 bmpstring_fmt().lemma_parse_safe(ibuf);
308 }
309 }
310
311 impl Productive for super::super::BmpStringFmt {
312 open spec fn productive_inv(&self) -> bool {
313 false
314 }
315
316 proof fn lemma_productive(&self, _s: Seq<u8>) {
317 }
318 }
319
320 impl SoundParser for super::super::BmpStringFmt {
321 proof fn lemma_parse_sound_consumption(&self, ibuf: Seq<u8>) {
322 lemma_bmpstring_fmt_sound_nonmal_inv();
323 bmpstring_fmt().lemma_parse_sound_consumption(ibuf);
324 }
325
326 proof fn lemma_parse_sound_value(&self, ibuf: Seq<u8>) {
327 lemma_bmpstring_fmt_sound_nonmal_inv();
328 bmpstring_fmt().lemma_parse_sound_value(ibuf);
329 }
330 }
331
332 impl GoodSerializer for super::super::BmpStringFmt {
333 proof fn lemma_serialize_len(&self, v: Self::SVal) {
334 bmpstring_fmt().lemma_serialize_len(v);
335 }
336 }
337
338 impl SPRoundTripDps for super::super::BmpStringFmt {
339 proof fn theorem_serialize_dps_parse_roundtrip(&self, v: Self::T, obuf: Seq<u8>) {
340 lemma_encode_bmp_string_valid(v.inner);
341 lemma_decode_encode_bmp_string(v.inner);
342 let bytes = encode_bmp_string(v.inner);
343 let inner = Refined(Tail, |bytes: Seq<u8>| is_valid_bmp_string(bytes));
344 inner.theorem_serialize_dps_parse_roundtrip(bytes, obuf);
345 }
346 }
347
348 impl NonMalleable for super::super::BmpStringFmt {
349 proof fn lemma_parse_non_malleable(&self, buf1: Seq<u8>, buf2: Seq<u8>) {
350 lemma_bmpstring_fmt_sound_nonmal_inv();
351 bmpstring_fmt().lemma_parse_non_malleable(buf1, buf2);
352 }
353 }
354
355 impl EquivSerializers for super::super::BmpStringFmt {
356 proof fn lemma_serialize_equiv_on_empty(&self, v: Self::SVal) {
357 bmpstring_fmt().lemma_serialize_equiv_on_empty(v);
358 }
359 }
360
361}
362
363pub fn check_valid_bmp_string(bytes: &[u8]) -> (res: bool)
365 ensures
366 res == is_valid_bmp_string(bytes.deep_view()),
367{
368 if bytes.len() % 2 != 0 {
369 return false;
370 }
371 let mut iter = 0..bytes.len() / 2;
372 let ghost indices = iter.remaining();
373 let valid = iter.all(
374 |i: usize| -> (valid: bool)
375 requires
376 i < bytes@.len() / 2,
377 ensures
378 valid == vstd::utf8::is_scalar(bmp_code_unit(bytes@, i as int)),
379 {
380 let unit = u16_from_be_bytes([bytes[2 * i], bytes[2 * i + 1]]) as u32;
381 super::utf8string::is_unicode_scalar(unit)
382 },
383 );
384 assert(bytes@ == bytes.deep_view());
385 assert forall|i: int| 0 <= i < indices.len() implies vstd::utf8::is_scalar(
387 bmp_code_unit(bytes@, indices[i] as int),
388 ) == vstd::utf8::is_scalar(#[trigger] bmp_code_unit(bytes@, i)) by {}
389
390 valid
391}
392
393#[cfg(feature = "alloc")]
396#[verifier::external_body]
397fn decode_bmp_string_owned(bytes: &[u8]) -> (res: String)
398 requires
399 is_valid_bmp_string(bytes.deep_view()),
400 ensures
401 res.deep_view() == decode_bmp_string(bytes.deep_view()),
402{
403 bytes.chunks_exact(2).map(
405 |pair| unsafe { char::from_u32_unchecked(u16::from_be_bytes([pair[0], pair[1]]) as u32) },
406 ).collect()
407}
408
409#[cfg(feature = "alloc")]
410impl<'i> Parser<&'i [u8]> for super::BmpStringFmt {
411 type PT = BmpString;
412
413 fn parse(&self, ibuf: &&'i [u8]) -> PResult<Self::PT> {
414 let (n, bytes) = Tail.parse(ibuf)?;
415 if !check_valid_bmp_string(bytes) {
416 Err(ParseError::custom("Invalid BMPString"))
417 } else {
418 let inner = decode_bmp_string_owned(bytes);
419 Ok((n, BmpString::new(inner)))
420 }
421 }
422}
423
424#[cfg(feature = "alloc")]
425impl<Output: OutputBuf> Serializer<Output, BmpString> for super::BmpStringFmt {
426 #[verifier::loop_isolation(false)]
427 fn serialize_into(&self, v: &BmpString, obuf: &mut Output) {
428 broadcast use crate::core::exec::output::outbuf_lemmas;
429
430 proof {
431 use_type_invariant(v);
432 lemma_encode_bmp_string_valid(v.deep_view().inner);
433 }
434 let value = v.inner.as_str();
435
436 let ghost initial = obuf@;
437 let ghost len = value.deep_view().len();
438 for c in iter: value.chars()
439 invariant
440 obuf@ == initial + encode_bmp_string(value.deep_view()[0..iter.index()]),
441 forall|n| old(obuf).fits(2 * iter.index() as nat + n) <==> obuf.fits(n),
442 old(obuf).same_destination(obuf),
443 {
444 proof {
445 old(obuf).lemma_fits_mono(2 * iter.index() as nat + 2, 2 * len as nat);
446 }
447 let pair = u16_to_be_bytes(c as u16);
448 obuf.write_bytes(&pair);
449 }
450 }
451}
452
453#[cfg(feature = "alloc")]
454impl Prepare<BmpString> for super::BmpStringFmt {
455 fn prepare(&self, v: &BmpString) -> Result<usize, PreSerializeError> {
456 proof {
457 use_type_invariant(v);
458 lemma_encode_bmp_string_valid(v.deep_view().inner);
459 }
460 v.inner.as_str().unicode_len().checked_mul(2).ok_or(PreSerializeError::length_too_large())
461 }
462}
463
464#[cfg(feature = "alloc")]
465impl ByteLen<BmpString> for super::BmpStringFmt {
466 fn length(&self, v: &BmpString) -> usize {
467 proof {
468 use_type_invariant(v);
469 }
470 v.inner.as_str().unicode_len() * 2
471 }
472}
473
474}