use alloc::{boxed::Box, string::String, vec::Vec};
use vstd::assert_seqs_equal;
use vstd::prelude::*;
verus! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Structural)]
pub enum CborFloat {
F16(u16),
F32(u32),
F64(u64),
}
impl DeepView for CborFloat {
type V = Self;
open spec fn deep_view(&self) -> Self::V {
*self
}
}
#[verifier::allow(autoderive_clone_without_spec)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CborBytes<'i> {
Definite(&'i [u8]),
Indefinite(Vec<u8>),
}
impl<'i> DeepView for CborBytes<'i> {
type V = Seq<u8>;
open spec fn deep_view(&self) -> Self::V {
match self {
Self::Definite(bytes) => bytes.deep_view(),
Self::Indefinite(bytes) => bytes.deep_view(),
}
}
}
#[verifier::allow(autoderive_clone_without_spec)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CborText<'i> {
Definite(&'i str),
Indefinite(String),
}
impl<'i> DeepView for CborText<'i> {
type V = Seq<char>;
open spec fn deep_view(&self) -> Self::V {
match self {
Self::Definite(text) => text.deep_view(),
Self::Indefinite(text) => text.deep_view(),
}
}
}
pub type CborArray<'i> = Vec<CborValue<'i>>;
pub type CborMap<'i> = Vec<(CborValue<'i>, CborValue<'i>)>;
#[derive(Debug, PartialEq, Eq)]
pub enum CborValue<'i> {
Integer(i128),
Bytes(CborBytes<'i>),
Text(CborText<'i>),
Array(CborArray<'i>),
Map(CborMap<'i>),
Tag(u64, Box<CborValue<'i>>),
Float(CborFloat),
Bool(bool),
Null,
Undefined,
Simple(u8),
}
pub enum CborValueSpec {
Integer(i128),
Bytes(Seq<u8>),
Text(Seq<char>),
Array(Seq<CborValueSpec>),
Map(Seq<(CborValueSpec, CborValueSpec)>),
Tag(u64, Box<CborValueSpec>),
Float(CborFloat),
Bool(bool),
Null,
Undefined,
Simple(u8),
}
pub open spec fn cbor_value_view(value: &CborValue) -> CborValueSpec
decreases *value,
{
match value {
CborValue::Integer(value) => CborValueSpec::Integer(*value),
CborValue::Bytes(value) => CborValueSpec::Bytes(value.deep_view()),
CborValue::Text(value) => CborValueSpec::Text(value.deep_view()),
CborValue::Array(values) => {
let seq = values@;
CborValueSpec::Array(
Seq::new(
seq.len(),
|i: int|
{
if 0 <= i < seq.len() {
cbor_value_view(&seq[i])
} else {
arbitrary()
}
},
),
)
},
CborValue::Map(values) => {
let seq = values@;
CborValueSpec::Map(
Seq::new(
seq.len(),
|i: int|
{
if 0 <= i < seq.len() {
(cbor_value_view(&seq[i].0), cbor_value_view(&seq[i].1))
} else {
arbitrary()
}
},
),
)
},
CborValue::Tag(tag, value) => {
CborValueSpec::Tag(*tag, Box::new(cbor_value_view(&**value)))
},
CborValue::Float(value) => CborValueSpec::Float(*value),
CborValue::Bool(value) => CborValueSpec::Bool(*value),
CborValue::Null => CborValueSpec::Null,
CborValue::Undefined => CborValueSpec::Undefined,
CborValue::Simple(value) => CborValueSpec::Simple(*value),
}
}
impl<'i> DeepView for CborValue<'i> {
type V = CborValueSpec;
open spec fn deep_view(&self) -> Self::V {
cbor_value_view(self)
}
}
pub proof fn lemma_collection_value_view(value: &CborValue)
ensures
match value {
CborValue::Array(values) => {
cbor_value_view(value) == CborValueSpec::Array(values.deep_view())
},
CborValue::Map(entries) => {
cbor_value_view(value) == CborValueSpec::Map(entries.deep_view())
},
_ => true,
},
decreases *value,
{
match value {
CborValue::Array(values) => {
let viewed = cbor_value_view(value);
let actual = match viewed {
CborValueSpec::Array(s) => s,
_ => arbitrary(),
};
assert_seqs_equal!(actual, values.deep_view(), i => {});
assert(viewed == CborValueSpec::Array(actual));
},
CborValue::Map(entries) => {
let viewed = cbor_value_view(value);
let actual = match viewed {
CborValueSpec::Map(s) => s,
_ => arbitrary(),
};
assert_seqs_equal!(actual, entries.deep_view(), i => {});
assert(viewed == CborValueSpec::Map(actual));
},
_ => {},
}
}
}