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 GeometryType,
40 I64,
42 #[cfg(feature = "unstable-v2")]
44 Alp(#[serde(serialize_with = "serialize_alp")] Alp),
45 U64,
47 F32,
49 F64,
51 Bytes,
53 #[cfg(feature = "unstable-v2")]
55 PackedBits,
56 #[cfg(feature = "unstable-v2")]
58 PresenceCoded(PresenceCoding),
59}
60
61#[cfg(feature = "unstable-v2")]
63fn serialize_alp<S: Serializer>(alp: &Alp, s: S) -> Result<S::Ok, S::Error> {
64 let mut st = s.serialize_struct("Alp", 3)?;
65 st.serialize_field("e", &alp.scale.e)?;
66 st.serialize_field("f", &alp.scale.f)?;
67 st.serialize_field("base", &alp.base)?;
68 st.end()
69}
70
71#[derive(Debug, Clone, Serialize)]
73pub struct BitField {
74 hi: u8,
76 lo: u8,
78 #[serde(serialize_with = "serialize_as_number")]
80 raw: u64,
81 meaning: String,
83}
84
85impl BitField {
86 pub fn mask(mask: u8, byte: u8, meaning: impl Into<String>) -> Self {
92 let (hi, lo) = mask_bounds(mask);
93 Self {
94 hi,
95 lo,
96 raw: u64::from((byte & mask) >> lo),
97 meaning: meaning.into(),
98 }
99 }
100
101 #[must_use]
107 pub fn flag(mask: u8, byte: u8, when_set: &str, when_clear: &str) -> Self {
108 debug_assert_eq!(mask.count_ones(), 1, "a flag occupies exactly one bit");
109 let meaning = if byte & mask == 0 {
110 when_clear
111 } else {
112 when_set
113 };
114 Self::mask(mask, byte, meaning)
115 }
116
117 #[must_use]
120 pub fn meaning(&self) -> &str {
121 &self.meaning
122 }
123}
124
125impl Display for BitField {
126 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
131 if self.hi == self.lo {
132 write!(f, "bit {}", self.hi)?;
133 } else {
134 write!(f, "bits {}-{}", self.hi, self.lo)?;
135 }
136 let width = usize::from(self.hi - self.lo + 1);
137 write!(f, " = {:0width$b} -> {}", self.raw, self.meaning)
138 }
139}
140
141#[expect(
143 clippy::cast_possible_truncation,
144 reason = "a u8 mask spans at most 8 bits"
145)]
146fn mask_bounds(mask: u8) -> (u8, u8) {
147 debug_assert!(mask != 0, "a bit field needs at least one bit");
148 let lo = mask.trailing_zeros() as u8;
149 let hi = (u8::BITS - 1 - mask.leading_zeros()) as u8;
150 debug_assert_eq!(
151 u32::from(hi - lo) + 1,
152 mask.count_ones(),
153 "a bit field's mask must be one contiguous run of bits"
154 );
155 (hi, lo)
156}
157
158#[derive(Debug, Clone, Copy)]
160pub struct BlobInfo {
161 pub meta: StreamMeta,
162 pub hint: DecodeHint,
163}
164
165impl Serialize for BlobInfo {
166 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
168 let mut st = s.serialize_struct("BlobInfo", 5)?;
169 st.serialize_field("streamType", &self.meta.stream_type.to_string())?;
170 st.serialize_field("logical", &self.meta.encoding.logical.to_string())?;
171 st.serialize_field("physical", &self.meta.encoding.physical.to_string())?;
172 st.serialize_field("numValues", &self.meta.num_values)?;
173 st.serialize_field("hint", &self.hint)?;
174 st.end()
175 }
176}
177
178fn serialize_as_number<T, S>(v: &T, s: S) -> Result<S::Ok, S::Error>
183where
184 T: Copy + TryInto<u32>,
185 S: Serializer,
186{
187 let n = (*v)
188 .try_into()
189 .map_err(|_| serde::ser::Error::custom("offset or count exceeds u32"))?;
190 s.serialize_u32(n)
191}
192
193#[derive(Debug, Clone, Serialize)]
198#[serde(rename_all = "camelCase")]
199pub struct Region {
200 #[serde(serialize_with = "serialize_as_number")]
202 pub offset: usize,
203 #[serde(serialize_with = "serialize_as_number")]
204 pub len: usize,
205 #[serde(serialize_with = "serialize_as_number")]
207 pub depth: usize,
208 pub label: String,
210 pub value: Option<String>,
212 pub bits: Vec<BitField>,
214 pub kind: RegionKind,
215 pub container: bool,
217 pub blob: Option<BlobInfo>,
219}
220
221#[derive(Serialize)]
223#[serde(rename_all = "camelCase")]
224pub struct DumpTree {
225 #[serde(serialize_with = "serialize_as_number")]
226 pub buf_len: usize,
227 pub regions: Vec<Region>,
229}
230
231pub const UNANNOTATED: &str = "<unannotated>";
233
234#[must_use]
238pub fn filter_layer(tree: &DumpTree, idx: usize) -> Option<DumpTree> {
239 let layer = tree
240 .regions
241 .iter()
242 .filter(|r| r.depth == 0 && r.container)
243 .nth(idx)?;
244 let start = layer.offset;
245 let end = layer.offset + layer.len;
246 let regions = tree
247 .regions
248 .iter()
249 .filter(|r| r.offset >= start && r.offset + r.len <= end)
250 .cloned()
251 .collect();
252 Some(DumpTree {
253 buf_len: tree.buf_len,
254 regions,
255 })
256}