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::codecs::presence_coding::PresenceCoding;
10#[cfg(feature = "unstable-v2")]
11use crate::wire::Alp;
12use crate::wire::StreamMeta;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
16#[serde(rename_all = "camelCase")]
17pub enum RegionKind {
18 Meta,
20 DataBlob,
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
28#[serde(tag = "kind", rename_all = "camelCase")]
29pub enum DecodeHint {
30 Presence,
32 Bool,
34 I32,
36 U32,
38 I64,
40 #[cfg(feature = "unstable-v2")]
42 Alp(#[serde(serialize_with = "serialize_alp")] Alp),
43 U64,
45 F32,
47 F64,
49 Bytes,
51 #[cfg(feature = "unstable-v2")]
53 PackedBits,
54 #[cfg(feature = "unstable-v2")]
56 PresenceCoded(PresenceCoding),
57}
58
59#[cfg(feature = "unstable-v2")]
61fn serialize_alp<S: Serializer>(alp: &Alp, s: S) -> Result<S::Ok, S::Error> {
62 let mut st = s.serialize_struct("Alp", 3)?;
63 st.serialize_field("e", &alp.scale.e)?;
64 st.serialize_field("f", &alp.scale.f)?;
65 st.serialize_field("base", &alp.base)?;
66 st.end()
67}
68
69#[derive(Debug, Clone, Serialize)]
71pub struct BitField {
72 hi: u8,
74 lo: u8,
76 #[serde(serialize_with = "serialize_as_number")]
78 raw: u64,
79 meaning: String,
81}
82
83impl BitField {
84 pub fn mask(mask: u8, byte: u8, meaning: impl Into<String>) -> Self {
90 let (hi, lo) = mask_bounds(mask);
91 Self {
92 hi,
93 lo,
94 raw: u64::from((byte & mask) >> lo),
95 meaning: meaning.into(),
96 }
97 }
98
99 #[must_use]
105 pub fn flag(mask: u8, byte: u8, when_set: &str, when_clear: &str) -> Self {
106 debug_assert_eq!(mask.count_ones(), 1, "a flag occupies exactly one bit");
107 let meaning = if byte & mask == 0 {
108 when_clear
109 } else {
110 when_set
111 };
112 Self::mask(mask, byte, meaning)
113 }
114
115 #[must_use]
118 pub fn meaning(&self) -> &str {
119 &self.meaning
120 }
121}
122
123impl Display for BitField {
124 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
129 if self.hi == self.lo {
130 write!(f, "bit {}", self.hi)?;
131 } else {
132 write!(f, "bits {}-{}", self.hi, self.lo)?;
133 }
134 let width = usize::from(self.hi - self.lo + 1);
135 write!(f, " = {:0width$b} -> {}", self.raw, self.meaning)
136 }
137}
138
139#[expect(
141 clippy::cast_possible_truncation,
142 reason = "a u8 mask spans at most 8 bits"
143)]
144fn mask_bounds(mask: u8) -> (u8, u8) {
145 debug_assert!(mask != 0, "a bit field needs at least one bit");
146 let lo = mask.trailing_zeros() as u8;
147 let hi = (u8::BITS - 1 - mask.leading_zeros()) as u8;
148 debug_assert_eq!(
149 u32::from(hi - lo) + 1,
150 mask.count_ones(),
151 "a bit field's mask must be one contiguous run of bits"
152 );
153 (hi, lo)
154}
155
156#[derive(Debug, Clone, Copy)]
158pub struct BlobInfo {
159 pub meta: StreamMeta,
160 pub hint: DecodeHint,
161}
162
163impl Serialize for BlobInfo {
164 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
166 let mut st = s.serialize_struct("BlobInfo", 5)?;
167 st.serialize_field("streamType", &self.meta.stream_type.to_string())?;
168 st.serialize_field("logical", &self.meta.encoding.logical.to_string())?;
169 st.serialize_field("physical", &self.meta.encoding.physical.to_string())?;
170 st.serialize_field("numValues", &self.meta.num_values)?;
171 st.serialize_field("hint", &self.hint)?;
172 st.end()
173 }
174}
175
176fn serialize_as_number<T, S>(v: &T, s: S) -> Result<S::Ok, S::Error>
181where
182 T: Copy + TryInto<u32>,
183 S: Serializer,
184{
185 let n = (*v)
186 .try_into()
187 .map_err(|_| serde::ser::Error::custom("offset or count exceeds u32"))?;
188 s.serialize_u32(n)
189}
190
191#[derive(Debug, Clone, Serialize)]
196#[serde(rename_all = "camelCase")]
197pub struct Region {
198 #[serde(serialize_with = "serialize_as_number")]
200 pub offset: usize,
201 #[serde(serialize_with = "serialize_as_number")]
202 pub len: usize,
203 #[serde(serialize_with = "serialize_as_number")]
205 pub depth: usize,
206 pub label: String,
208 pub value: Option<String>,
210 pub bits: Vec<BitField>,
212 pub kind: RegionKind,
213 pub container: bool,
215 pub blob: Option<BlobInfo>,
217}
218
219#[derive(Serialize)]
221#[serde(rename_all = "camelCase")]
222pub struct DumpTree {
223 #[serde(serialize_with = "serialize_as_number")]
224 pub buf_len: usize,
225 pub regions: Vec<Region>,
227}
228
229pub const UNANNOTATED: &str = "<unannotated>";
231
232#[must_use]
236pub fn filter_layer(tree: &DumpTree, idx: usize) -> Option<DumpTree> {
237 let layer = tree
238 .regions
239 .iter()
240 .filter(|r| r.depth == 0 && r.container)
241 .nth(idx)?;
242 let start = layer.offset;
243 let end = layer.offset + layer.len;
244 let regions = tree
245 .regions
246 .iter()
247 .filter(|r| r.offset >= start && r.offset + r.len <= end)
248 .cloned()
249 .collect();
250 Some(DumpTree {
251 buf_len: tree.buf_len,
252 regions,
253 })
254}