1use std::fmt::{Display, Formatter, Result as FmtResult};
4
5use serde::ser::SerializeStruct as _;
6use serde::{Serialize, Serializer};
7
8#[cfg(feature = "unstable-v2")]
9use crate::wire::Alp;
10use crate::wire::StreamMeta;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
14#[serde(rename_all = "camelCase")]
15pub enum RegionKind {
16 Meta,
18 DataBlob,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
26#[serde(tag = "kind", rename_all = "camelCase")]
27pub enum DecodeHint {
28 Presence,
30 Bool,
32 I32,
34 U32,
36 I64,
38 #[cfg(feature = "unstable-v2")]
40 Alp(#[serde(serialize_with = "serialize_alp")] Alp),
41 U64,
43 F32,
45 F64,
47 Bytes,
49 #[cfg(feature = "unstable-v2")]
51 PackedBits,
52}
53
54#[cfg(feature = "unstable-v2")]
56fn serialize_alp<S: Serializer>(alp: &Alp, s: S) -> Result<S::Ok, S::Error> {
57 let mut st = s.serialize_struct("Alp", 3)?;
58 st.serialize_field("e", &alp.scale.e)?;
59 st.serialize_field("f", &alp.scale.f)?;
60 st.serialize_field("base", &alp.base)?;
61 st.end()
62}
63
64#[derive(Debug, Clone, Serialize)]
66pub struct BitField {
67 hi: u8,
69 lo: u8,
71 #[serde(serialize_with = "serialize_as_number")]
73 raw: u64,
74 meaning: String,
76}
77
78impl BitField {
79 pub fn mask(mask: u8, byte: u8, meaning: impl Into<String>) -> Self {
85 let (hi, lo) = mask_bounds(mask);
86 Self {
87 hi,
88 lo,
89 raw: u64::from((byte & mask) >> lo),
90 meaning: meaning.into(),
91 }
92 }
93
94 #[must_use]
100 pub fn flag(mask: u8, byte: u8, when_set: &str, when_clear: &str) -> Self {
101 debug_assert_eq!(mask.count_ones(), 1, "a flag occupies exactly one bit");
102 let meaning = if byte & mask == 0 {
103 when_clear
104 } else {
105 when_set
106 };
107 Self::mask(mask, byte, meaning)
108 }
109
110 #[must_use]
113 pub fn meaning(&self) -> &str {
114 &self.meaning
115 }
116}
117
118impl Display for BitField {
119 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
124 if self.hi == self.lo {
125 write!(f, "bit {}", self.hi)?;
126 } else {
127 write!(f, "bits {}-{}", self.hi, self.lo)?;
128 }
129 let width = usize::from(self.hi - self.lo + 1);
130 write!(f, " = {:0width$b} -> {}", self.raw, self.meaning)
131 }
132}
133
134#[expect(
136 clippy::cast_possible_truncation,
137 reason = "a u8 mask spans at most 8 bits"
138)]
139fn mask_bounds(mask: u8) -> (u8, u8) {
140 debug_assert!(mask != 0, "a bit field needs at least one bit");
141 let lo = mask.trailing_zeros() as u8;
142 let hi = (u8::BITS - 1 - mask.leading_zeros()) as u8;
143 debug_assert_eq!(
144 u32::from(hi - lo) + 1,
145 mask.count_ones(),
146 "a bit field's mask must be one contiguous run of bits"
147 );
148 (hi, lo)
149}
150
151#[derive(Debug, Clone, Copy)]
153pub struct BlobInfo {
154 pub meta: StreamMeta,
155 pub hint: DecodeHint,
156}
157
158impl Serialize for BlobInfo {
159 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
161 let mut st = s.serialize_struct("BlobInfo", 5)?;
162 st.serialize_field("streamType", &self.meta.stream_type.to_string())?;
163 st.serialize_field("logical", &self.meta.encoding.logical.to_string())?;
164 st.serialize_field("physical", &self.meta.encoding.physical.to_string())?;
165 st.serialize_field("numValues", &self.meta.num_values)?;
166 st.serialize_field("hint", &self.hint)?;
167 st.end()
168 }
169}
170
171fn serialize_as_number<T, S>(v: &T, s: S) -> Result<S::Ok, S::Error>
176where
177 T: Copy + TryInto<u32>,
178 S: Serializer,
179{
180 let n = (*v)
181 .try_into()
182 .map_err(|_| serde::ser::Error::custom("offset or count exceeds u32"))?;
183 s.serialize_u32(n)
184}
185
186#[derive(Debug, Clone, Serialize)]
191#[serde(rename_all = "camelCase")]
192pub struct Region {
193 #[serde(serialize_with = "serialize_as_number")]
195 pub offset: usize,
196 #[serde(serialize_with = "serialize_as_number")]
197 pub len: usize,
198 #[serde(serialize_with = "serialize_as_number")]
200 pub depth: usize,
201 pub label: String,
203 pub value: Option<String>,
205 pub bits: Vec<BitField>,
207 pub kind: RegionKind,
208 pub container: bool,
210 pub blob: Option<BlobInfo>,
212}
213
214#[derive(Serialize)]
216#[serde(rename_all = "camelCase")]
217pub struct DumpTree {
218 #[serde(serialize_with = "serialize_as_number")]
219 pub buf_len: usize,
220 pub regions: Vec<Region>,
222}
223
224pub const UNANNOTATED: &str = "<unannotated>";
226
227#[must_use]
231pub fn filter_layer(tree: &DumpTree, idx: usize) -> Option<DumpTree> {
232 let layer = tree
233 .regions
234 .iter()
235 .filter(|r| r.depth == 0 && r.container)
236 .nth(idx)?;
237 let start = layer.offset;
238 let end = layer.offset + layer.len;
239 let regions = tree
240 .regions
241 .iter()
242 .filter(|r| r.offset >= start && r.offset + r.len <= end)
243 .cloned()
244 .collect();
245 Some(DumpTree {
246 buf_len: tree.buf_len,
247 regions,
248 })
249}