substrate_data/wire/frame/
shaped.rs1use super::Unpacker;
7use crate::model::value::{Map, Value};
8use crate::schema::{EnumShape, Shape, StructShape};
9
10const F32_BITS: u32 = 32;
12
13#[must_use]
15pub fn read_shaped(bytes: &[u8], shape: &Shape) -> Option<Value> {
16 let mut u = Unpacker::open(bytes)?;
17 let v = unpack_shaped(&mut u, shape)?;
18 u.at_end().then_some(v)
19}
20
21pub fn unpack_shaped(u: &mut Unpacker<'_>, shape: &Shape) -> Option<Value> {
23 Some(match shape {
24 Shape::Bool => Value::Bool(u.bool()?),
25 Shape::Int { .. } => Value::Int(u.int()?),
26 Shape::Float { bits } if *bits == F32_BITS => Value::Float(f64::from(u.f32()?)),
27 Shape::Float { .. } => Value::Float(u.f64()?),
28 Shape::Str => Value::Str(crate::typed::escape_at(u.str()?)),
30 Shape::Atom => Value::Str(crate::typed::escape_at(
31 crate::Atom::from_number(u32::try_from(u.uint()?).ok()?)?.as_str(),
32 )),
33 Shape::Named(named) => unpack_shaped(u, &named.stored())?,
35 Shape::Ref { kinds, id } => Value::Ref(unpack_ref(u, kinds, &id())?),
38 Shape::Bytes => Value::Bytes(u.bytes()?.to_vec()),
39 Shape::Optional(inner) => optional(u, &inner())?,
40 Shape::List(item) => list(u, &item())?,
41 Shape::Struct(s) => record(u, s)?,
42 Shape::Enum(e) if e.tag.is_none() => names(u, e)?,
43 _ => u.tagged::<Value>()?,
44 })
45}
46
47fn optional(u: &mut Unpacker<'_>, inner: &Shape) -> Option<Value> {
49 if u.bool()? {
50 unpack_shaped(u, inner)
51 } else {
52 Some(Value::Null)
53 }
54}
55
56fn unpack_ref(u: &mut Unpacker<'_>, kinds: &[&str], id: &Shape) -> Option<crate::Ref> {
59 let Some(kind) = kinds.first() else {
60 return Some(crate::Ref::new(
61 crate::KindName::new(u.str()?).ok()?,
62 crate::RefKey::new(u.str()?).ok()?,
63 ));
64 };
65 Some(crate::Ref::new(
66 crate::KindName::new(kind).ok()?,
67 crate::RefKey::new(&unpack_id(u, id)?).ok()?,
68 ))
69}
70
71fn unpack_id(u: &mut Unpacker<'_>, shape: &Shape) -> Option<String> {
73 match shape {
74 Shape::Int { .. } => Some(u.int()?.to_string()),
75 Shape::Named(named) => unpack_id(u, &named.stored()),
76 _ => Some(u.str()?.to_owned()),
77 }
78}
79
80fn list(u: &mut Unpacker<'_>, item: &Shape) -> Option<Value> {
82 Some(Value::List(match item {
83 Shape::Int { min, .. } if *min < 0 => {
84 u.uints(|v| Some(Value::Int(crate::binary::unzigzag(v))))?
85 }
86 Shape::Int { max, .. } if *max == i64::MAX => {
89 u.uints(|v| Some(Value::Int(v.cast_signed())))?
90 }
91 Shape::Int { .. } => u.uints(|v| i64::try_from(v).ok().map(Value::Int))?,
92 Shape::Float { bits } if *bits == F32_BITS => u
93 .f32s()?
94 .into_iter()
95 .map(|f| Value::Float(f64::from(f)))
96 .collect(),
97 Shape::Float { .. } => u.f64s()?.into_iter().map(Value::Float).collect(),
98 _ => {
99 let (n, end) = u.list()?;
100 let items = (0..n)
101 .map(|_| unpack_shaped(u, item))
102 .collect::<Option<_>>()?;
103 u.skip_to(end)?;
104 items
105 }
106 }))
107}
108
109fn record(u: &mut Unpacker<'_>, s: &StructShape) -> Option<Value> {
112 let end = u.begin()?;
113 let mut m = Map::new();
114 for field in &s.fields {
115 if !u.more(end) {
116 break;
117 }
118 m.insert(field.name, unpack_shaped(u, &(field.shape)())?);
119 }
120 u.leave(end)?;
121 Some(Value::Map(m))
122}
123
124fn names(u: &mut Unpacker<'_>, e: &EnumShape) -> Option<Value> {
126 let i = usize::try_from(u.uint()?).ok()?;
127 Some(Value::Str(e.variants.get(i)?.name.to_owned()))
128}