1use super::iterators::{ArrayIter, BytesIter, DictIter, StringIter};
2use crate::{constants::TAG_CBOR_ITEM, Cbor, CborValue, DebugUsingDisplay, Tags};
3use std::fmt::{Debug, Display, Formatter, Write};
4
5#[derive(PartialEq, PartialOrd, Clone, Copy)]
12pub enum ItemKind<'a> {
13 Pos(u64),
14 Neg(u64),
15 Float(f64),
16 Str(StringIter<'a>),
17 Bytes(BytesIter<'a>),
18 Bool(bool),
19 Null,
20 Undefined,
21 Simple(u8),
22 Array(ArrayIter<'a>),
23 Dict(DictIter<'a>),
24}
25
26impl<'a> Debug for ItemKind<'a> {
27 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
28 match self {
29 Self::Pos(arg0) => f.debug_tuple("Pos").field(arg0).finish(),
30 Self::Neg(arg0) => f.debug_tuple("Neg").field(arg0).finish(),
31 Self::Float(arg0) => f.debug_tuple("Float").field(arg0).finish(),
32 Self::Str(arg0) => f
33 .debug_tuple("Str")
34 .field(&DebugUsingDisplay(arg0))
35 .finish(),
36 Self::Bytes(arg0) => f
37 .debug_tuple("Bytes")
38 .field(&DebugUsingDisplay(arg0))
39 .finish(),
40 Self::Bool(arg0) => f.debug_tuple("Bool").field(arg0).finish(),
41 Self::Null => write!(f, "Null"),
42 Self::Undefined => write!(f, "Undefined"),
43 Self::Simple(arg0) => f.debug_tuple("Simple").field(arg0).finish(),
44 Self::Array(arg0) => write!(f, "Array({:?})", arg0.size()),
45 Self::Dict(arg0) => write!(f, "Dict({:?})", arg0.size()),
46 }
47 }
48}
49
50impl<'a> Display for ItemKind<'a> {
51 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
52 match self {
53 ItemKind::Pos(_) => write!(f, "positive number"),
54 ItemKind::Neg(_) => write!(f, "negative number"),
55 ItemKind::Float(_) => write!(f, "floating-point number"),
56 ItemKind::Str(_) => write!(f, "text string"),
57 ItemKind::Bytes(_) => write!(f, "byte string"),
58 ItemKind::Bool(_) => write!(f, "boolean"),
59 ItemKind::Null => write!(f, "null"),
60 ItemKind::Undefined => write!(f, "undefined"),
61 ItemKind::Simple(_) => write!(f, "simple value"),
62 ItemKind::Array(_) => write!(f, "array"),
63 ItemKind::Dict(_) => write!(f, "dictionary"),
64 }
65 }
66}
67
68impl<'a> ItemKind<'a> {
69 pub fn new(cbor: &'a Cbor) -> Self {
70 super::item(cbor.as_slice())
71 }
72}
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75pub enum ItemKindShort {
76 Pos,
77 Neg,
78 Float,
79 Str,
80 Bytes,
81 Bool,
82 Null,
83 Undefined,
84 Simple,
85 Array,
86 Dict,
87}
88
89impl Display for ItemKindShort {
90 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
91 match self {
92 ItemKindShort::Pos => write!(f, "positive number"),
93 ItemKindShort::Neg => write!(f, "negative number"),
94 ItemKindShort::Float => write!(f, "floating-point number"),
95 ItemKindShort::Str => write!(f, "text string"),
96 ItemKindShort::Bytes => write!(f, "byte string"),
97 ItemKindShort::Bool => write!(f, "boolean"),
98 ItemKindShort::Null => write!(f, "null"),
99 ItemKindShort::Undefined => write!(f, "undefined"),
100 ItemKindShort::Simple => write!(f, "simple value"),
101 ItemKindShort::Array => write!(f, "array"),
102 ItemKindShort::Dict => write!(f, "dictionary"),
103 }
104 }
105}
106
107impl<'a> From<ItemKind<'a>> for ItemKindShort {
108 fn from(kind: ItemKind<'a>) -> Self {
109 match kind {
110 ItemKind::Pos(_) => ItemKindShort::Pos,
111 ItemKind::Neg(_) => ItemKindShort::Neg,
112 ItemKind::Float(_) => ItemKindShort::Float,
113 ItemKind::Str(_) => ItemKindShort::Str,
114 ItemKind::Bytes(_) => ItemKindShort::Bytes,
115 ItemKind::Bool(_) => ItemKindShort::Bool,
116 ItemKind::Null => ItemKindShort::Null,
117 ItemKind::Undefined => ItemKindShort::Undefined,
118 ItemKind::Simple(_) => ItemKindShort::Simple,
119 ItemKind::Array(_) => ItemKindShort::Array,
120 ItemKind::Dict(_) => ItemKindShort::Dict,
121 }
122 }
123}
124
125#[derive(Clone, Copy, PartialEq)]
133pub struct TaggedItem<'a> {
134 tags: Tags<'a>,
135 kind: ItemKind<'a>,
136 cbor: &'a Cbor,
137}
138
139impl<'a> Debug for TaggedItem<'a> {
140 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141 write!(f, "TaggedItem({}, {:?})", self.tags, self.kind)
142 }
143}
144
145struct W([u8; 32], u8);
146impl W {
147 pub fn new() -> Self {
148 Self([0; 32], 0)
149 }
150 pub fn as_str(&self) -> &str {
151 unsafe { std::str::from_utf8_unchecked(&self.0.as_ref()[0..self.1 as usize]) }
152 }
153}
154impl std::fmt::Write for W {
155 fn write_str(&mut self, s: &str) -> std::fmt::Result {
156 let end = self.1 as usize + s.len();
157 if end > 24 {
158 Err(std::fmt::Error)
159 } else {
160 self.0.as_mut()[self.1 as usize..end].copy_from_slice(s.as_bytes());
161 self.1 = end as u8;
162 Ok(())
163 }
164 }
165}
166
167#[allow(clippy::many_single_char_names)]
168fn write_float(f: &mut std::fmt::Formatter<'_>, x: f64) -> std::fmt::Result {
169 if x == f64::INFINITY {
170 write!(f, "Infinity")
171 } else if x == f64::NEG_INFINITY {
172 write!(f, "-Infinity")
173 } else if x.is_nan() {
174 write!(f, "NaN")
175 } else {
176 let mut w = W::new();
177 if x != 0.0 && (x.abs() < 1e-6 || x.abs() > 1e16) {
178 write!(w, "{:e}", x)?;
179 } else {
180 write!(w, "{}", x)?;
181 }
182 let s = w.as_str();
183
184 let e = s.find('e').unwrap_or(s.len());
185 let (mantissa, exponent) = s.split_at(e);
186 write!(f, "{}", mantissa)?;
187 if !mantissa.contains('.') {
188 write!(f, ".0")?;
189 }
190 write!(f, "{}", exponent)?;
191 Ok(())
192 }
193}
194
195impl<'a> Display for TaggedItem<'a> {
196 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
197 if let (Some(TAG_CBOR_ITEM), ItemKind::Bytes(bytes)) = (self.tags().single(), self.kind()) {
198 let indefinite = if bytes.is_indefinite() { "_ " } else { "" };
199 let bytes = bytes.as_cow();
200 let cbor = Cbor::unchecked(bytes.as_ref());
201 return write!(f, "<{}{}>", indefinite, cbor);
202 }
203
204 let mut parens = 0;
205 for tag in self.tags() {
206 write!(f, "{}(", tag)?;
207 parens += 1;
208 }
209 match self.kind() {
210 ItemKind::Pos(x) => write!(f, "{}", x)?,
211 ItemKind::Neg(x) => write!(f, "{}", -1 - (i128::from(x)))?,
212 ItemKind::Float(x) => write_float(f, x)?,
213 ItemKind::Str(mut s) => {
214 if s.is_indefinite() {
215 if s.is_empty() {
216 write!(f, "\"\"_")?;
217 } else {
218 write!(f, "(_")?;
219 let mut first = true;
220 for s in s {
221 if first {
222 first = false;
223 } else {
224 write!(f, ",")?;
225 }
226 write!(f, " \"{}\"", s.escape_debug())?;
227 }
228 write!(f, ")")?;
229 }
230 } else {
231 let s = s.next().unwrap();
232 write!(f, "\"{}\"", s.escape_debug())?;
233 }
234 }
235 ItemKind::Bytes(mut b) => {
236 if b.is_indefinite() {
237 if b.is_empty() {
238 write!(f, "''_")?;
239 } else {
240 write!(f, "(_")?;
241 let mut first = true;
242 for b in b {
243 if first {
244 first = false;
245 } else {
246 write!(f, ",")?;
247 }
248 write!(f, " h'")?;
249 for byte in b {
250 write!(f, "{:02x}", byte)?;
251 }
252 write!(f, "'")?;
253 }
254 write!(f, ")")?;
255 }
256 } else {
257 let b = b.next().unwrap();
258 write!(f, "h'")?;
259 for byte in b {
260 write!(f, "{:02x}", byte)?;
261 }
262 write!(f, "'")?;
263 }
264 }
265 ItemKind::Bool(b) => write!(f, "{}", b)?,
266 ItemKind::Null => write!(f, "null")?,
267 ItemKind::Undefined => write!(f, "undefined")?,
268 ItemKind::Simple(s) => write!(f, "simple({})", s)?,
269 ItemKind::Array(_) => unreachable!(),
270 ItemKind::Dict(_) => unreachable!(),
271 }
272 for _ in 0..parens {
273 write!(f, ")")?;
274 }
275 Ok(())
276 }
277}
278
279impl<'a> TaggedItem<'a> {
280 pub fn new(cbor: &'a Cbor) -> Self {
281 let (tags, kind) = super::tagged_item(cbor.as_ref());
282 Self { tags, kind, cbor }
283 }
284
285 pub fn decode(self) -> CborValue<'a> {
291 CborValue::new(self)
292 }
293
294 pub fn tags(&self) -> Tags<'a> {
296 self.tags
297 }
298
299 pub fn kind(&self) -> ItemKind<'a> {
301 self.kind
302 }
303
304 pub fn cbor(&self) -> &'a Cbor {
306 self.cbor
307 }
308}