1use self::{CborValue::*, Number::*};
2use crate::{constants::*, Cbor, CborOwned, ItemKind, TaggedItem};
3use std::{
4 borrow::Cow,
5 collections::{btree_map::Entry, BTreeMap},
6 fmt::Debug,
7};
8
9mod number;
10mod timestamp;
11
12pub use number::{Exponential, Number};
13pub use timestamp::{Precision, Timestamp};
14
15#[derive(Debug, Clone, PartialEq)]
22pub enum CborValue<'a> {
23 Array(Vec<Cow<'a, Cbor>>),
24 Dict(BTreeMap<Cow<'a, Cbor>, Cow<'a, Cbor>>),
25 Undefined,
26 Null,
27 Bool(bool),
28 Number(Number<'a>),
29 Timestamp(Timestamp),
30 Str(Cow<'a, str>),
31 Bytes(Cow<'a, [u8]>),
32 Invalid,
34 Unknown,
36}
37
38impl<'a> CborValue<'a> {
39 pub fn new(item: TaggedItem<'a>) -> Self {
40 Self::from_item(item).unwrap_or(Invalid)
41 }
42
43 fn from_item(item: TaggedItem<'a>) -> Option<Self> {
44 match item.tags().single() {
45 #[cfg(feature = "rfc3339")]
46 Some(TAG_ISO8601) => Timestamp::from_string(item).map(Timestamp),
47 Some(TAG_EPOCH) => Timestamp::from_epoch(item).map(Timestamp),
48 Some(TAG_BIGNUM_POS | TAG_BIGNUM_NEG) => {
49 Some(Number(Decimal(Exponential::from_bytes(item)?)))
50 }
51 Some(TAG_BIGDECIMAL | TAG_BIGFLOAT) => Number::from_bignum(item).map(CborValue::Number),
52 Some(TAG_CBOR_ITEM) => {
53 if let ItemKind::Bytes(b) = item.kind() {
54 if let Some(b) = b.as_slice() {
55 Some(Cbor::unchecked(b).decode())
56 } else {
57 Some(CborOwned::unchecked(b.to_vec()).decode().make_static())
58 }
59 } else {
60 None
61 }
62 }
63 Some(t @ (TAG_BASE64 | TAG_BASE64URL)) => {
64 if let ItemKind::Str(s) = item.kind() {
65 let s = s.as_cow();
66 let b = if t == TAG_BASE64 {
67 base64::decode(s.as_bytes())
68 } else {
69 base64::decode_config(s.as_bytes(), base64::URL_SAFE_NO_PAD)
70 };
71 b.map(|bytes| Bytes(Cow::Owned(bytes))).ok()
72 } else {
73 None
74 }
75 }
76 None => Some(match item.kind() {
77 ItemKind::Pos(x) => Number(Int(x.into())),
78 ItemKind::Neg(x) => Number(Int(-1_i128 - i128::from(x))),
79 ItemKind::Float(f) => Number(IEEE754(f)),
80 ItemKind::Str(s) => Str(s.as_cow()),
81 ItemKind::Bytes(b) => Bytes(b.as_cow()),
82 ItemKind::Bool(b) => Bool(b),
83 ItemKind::Null => Null,
84 ItemKind::Undefined => Undefined,
85 ItemKind::Simple(_) => Unknown,
86 ItemKind::Array(a) => Array(a.map(Cow::Borrowed).collect()),
87 ItemKind::Dict(d) => Dict(d.fold(BTreeMap::new(), |mut acc, (k, v)| {
88 if let Entry::Vacant(e) = acc.entry(Cow::Borrowed(k)) {
89 e.insert(Cow::Borrowed(v));
90 }
91 acc
92 })),
93 }),
94 _ => Some(Unknown),
95 }
96 }
97
98 pub fn is_undefined(&self) -> bool {
99 matches!(self, Undefined)
100 }
101
102 pub fn is_null(&self) -> bool {
103 matches!(self, Null)
104 }
105
106 pub fn is_unknown(&self) -> bool {
107 matches!(self, Unknown)
108 }
109
110 pub fn is_invalid(&self) -> bool {
111 matches!(self, Invalid)
112 }
113
114 pub fn as_bool(&self) -> Option<bool> {
115 if let Bool(b) = self {
116 Some(*b)
117 } else {
118 None
119 }
120 }
121
122 pub fn as_number(&self) -> Option<&Number> {
123 if let Number(n) = self {
124 Some(n)
125 } else {
126 None
127 }
128 }
129
130 pub fn to_number(self) -> Option<Number<'a>> {
131 if let Number(n) = self {
132 Some(n)
133 } else {
134 None
135 }
136 }
137
138 pub fn as_timestamp(&self) -> Option<Timestamp> {
139 if let Timestamp(t) = self {
140 Some(*t)
141 } else {
142 None
143 }
144 }
145
146 pub fn as_str(&self) -> Option<&Cow<'a, str>> {
147 if let Str(s) = self {
148 Some(s)
149 } else {
150 None
151 }
152 }
153
154 pub fn to_str(self) -> Option<Cow<'a, str>> {
155 if let Str(s) = self {
156 Some(s)
157 } else {
158 None
159 }
160 }
161
162 pub fn as_bytes(&self) -> Option<&Cow<'a, [u8]>> {
163 if let Bytes(b) = self {
164 Some(b)
165 } else {
166 None
167 }
168 }
169
170 pub fn to_bytes(self) -> Option<Cow<'a, [u8]>> {
171 if let Bytes(b) = self {
172 Some(b)
173 } else {
174 None
175 }
176 }
177
178 pub fn as_array(&self) -> Option<&[Cow<'a, Cbor>]> {
179 if let Array(a) = self {
180 Some(a.as_slice())
181 } else {
182 None
183 }
184 }
185
186 pub fn to_array(self) -> Option<Vec<Cow<'a, Cbor>>> {
187 if let Array(a) = self {
188 Some(a)
189 } else {
190 None
191 }
192 }
193
194 pub fn as_dict(&self) -> Option<&BTreeMap<Cow<'a, Cbor>, Cow<'a, Cbor>>> {
195 if let Dict(a) = self {
196 Some(a)
197 } else {
198 None
199 }
200 }
201
202 pub fn to_dict(self) -> Option<BTreeMap<Cow<'a, Cbor>, Cow<'a, Cbor>>> {
203 if let Dict(a) = self {
204 Some(a)
205 } else {
206 None
207 }
208 }
209
210 pub fn make_static(self) -> CborValue<'static> {
212 match self {
213 Array(a) => Array(a.into_iter().map(ms).collect()),
214 Dict(d) => Dict(d.into_iter().map(|(k, v)| (ms(k), ms(v))).collect()),
215 Undefined => Undefined,
216 Null => Null,
217 Bool(b) => Bool(b),
218 Number(n) => Number(n.make_static()),
219 Timestamp(t) => Timestamp(t),
220 Str(s) => Str(ms(s)),
221 Bytes(b) => Bytes(ms(b)),
222 Invalid => Invalid,
223 Unknown => Unknown,
224 }
225 }
226}
227
228fn ms<'a, T: ToOwned + ?Sized + 'a>(c: Cow<'a, T>) -> Cow<'static, T> {
229 match c {
230 Cow::Borrowed(b) => Cow::Owned(b.to_owned()),
231 Cow::Owned(o) => Cow::Owned(o),
232 }
233}
234
235#[cfg(test)]
236mod tests {
237 use crate::{
238 constants::*,
239 value::{number::Exponential, Number, Timestamp},
240 CborBuilder, CborOwned, CborValue, Encoder, Literal, Writer,
241 };
242
243 #[test]
244 fn test_str_lifetime() {
245 fn _check_compile<'a, 'err: 'a>(value: &'a CborValue<'err>) -> &'err str {
246 match value.as_str().unwrap() {
247 std::borrow::Cow::Borrowed(b) => *b,
248 std::borrow::Cow::Owned(_) => todo!(),
249 }
250 }
251 }
252
253 #[test]
254 fn test_bytes_lifetime() {
255 fn _check_compile<'a, 'err: 'a>(value: &'a CborValue<'err>) -> &'err [u8] {
256 match value.as_bytes().unwrap() {
257 std::borrow::Cow::Borrowed(b) => *b,
258 std::borrow::Cow::Owned(_) => todo!(),
259 }
260 }
261 }
262
263 #[test]
264 fn display() {
265 fn to_cbor_str(f: f64) -> String {
266 format!("{}", CborBuilder::new().encode_f64(f))
267 }
268 assert_eq!(to_cbor_str(1.0), "1.0");
269 assert_eq!(to_cbor_str(-1.1), "-1.1");
270 assert_eq!(to_cbor_str(0.0), "0.0");
271 assert_eq!(to_cbor_str(-0.0), "-0.0");
272 }
273
274 #[test]
275 fn base64string() {
276 fn to_cbor(s: &str, tag: u64) -> CborOwned {
277 let mut v = vec![0xd8u8, tag as u8, 0x60 | (s.len() as u8)];
278 v.extend_from_slice(s.as_bytes());
279 CborOwned::unchecked(v)
280 }
281 fn b(bytes: &CborOwned) -> Vec<u8> {
282 if let CborValue::Bytes(bytes) = bytes.decode() {
283 bytes.into_owned()
284 } else {
285 panic!("no bytes: {}", bytes)
286 }
287 }
288
289 let bytes = to_cbor("a346_-0=", TAG_BASE64URL);
290 assert_eq!(b(&bytes), vec![107, 126, 58, 255, 237]);
291
292 let bytes = to_cbor("a346_-0", TAG_BASE64URL);
293 assert_eq!(b(&bytes), vec![107, 126, 58, 255, 237]);
294
295 let bytes = to_cbor("a346/+0=", TAG_BASE64);
296 assert_eq!(b(&bytes), vec![107, 126, 58, 255, 237]);
297
298 let bytes = to_cbor("a346/+0", TAG_BASE64);
299 assert_eq!(b(&bytes), vec![107, 126, 58, 255, 237]);
300 }
301
302 #[test]
303 fn tags() {
304 let cbor = CborBuilder::new().write_null([1, 2, 3]);
305 assert_eq!(cbor.tags().last(), Some(3));
306 assert_eq!(cbor.tags().first(), Some(1));
307 assert_eq!(cbor.tags().single(), None);
308
309 let cbor = CborBuilder::new().write_null([4]);
310 assert_eq!(cbor.tags().last(), Some(4));
311 assert_eq!(cbor.tags().first(), Some(4));
312 assert_eq!(cbor.tags().single(), Some(4));
313 }
314
315 #[test]
316 #[cfg(feature = "rfc3339")]
317 fn rfc3339() {
318 let cbor = CborBuilder::new().write_str("1983-03-22T12:17:05.345+02:00", [TAG_ISO8601]);
319 assert_eq!(
320 cbor.decode(),
321 CborValue::Timestamp(Timestamp::new(417176225, 345_000_000, 7200))
322 );
323
324 let cbor = CborBuilder::new().write_str("2183-03-22T12:17:05.345-03:00", [TAG_ISO8601]);
325 assert_eq!(
326 cbor.decode(),
327 CborValue::Timestamp(Timestamp::new(6728627825, 345_000_000, -10800))
328 );
329
330 let cbor = CborBuilder::new().write_str("1833-03-22T02:17:05.345-13:00", [TAG_ISO8601]);
331 assert_eq!(
332 cbor.decode(),
333 CborValue::Timestamp(Timestamp::new(-4316316175, 345_000_000, -46800))
334 );
335 }
336
337 #[test]
338 fn epoch() {
339 let cbor = CborBuilder::new().write_pos(1234567, [TAG_EPOCH]);
340 assert_eq!(
341 cbor.decode(),
342 CborValue::Timestamp(Timestamp::new(1234567, 0, 0))
343 );
344
345 let cbor = CborBuilder::new().write_neg(1234566, [TAG_EPOCH]);
346 assert_eq!(
347 cbor.decode(),
348 CborValue::Timestamp(Timestamp::new(-1234567, 0, 0))
349 );
350
351 let cbor = CborBuilder::new()
352 .write_lit(Literal::L8(2_345.900_000_014_5_f64.to_bits()), [TAG_EPOCH]);
353 assert_eq!(
354 cbor.decode(),
355 CborValue::Timestamp(Timestamp::new(2345, 900_000_015, 0))
356 );
357
358 let cbor = CborBuilder::new()
359 .write_lit(Literal::L8(2_345.900_000_015_5_f64.to_bits()), [TAG_EPOCH]);
360 assert_eq!(
361 cbor.decode(),
362 CborValue::Timestamp(Timestamp::new(2345, 900_000_016, 0))
363 );
364 }
365
366 #[test]
367 fn bignum() {
368 let cbor = CborBuilder::new().write_array([TAG_BIGFLOAT], |b| {
369 b.write_neg(2, []);
370 b.write_pos(13, []);
371 });
372 assert_eq!(
373 cbor.decode(),
374 CborValue::Number(Number::Float(Exponential::new(
375 -3,
376 [13_u8][..].into(),
377 false,
378 )))
379 );
380
381 let cbor = CborBuilder::new().write_array([TAG_BIGFLOAT], |b| {
382 b.write_neg(2, []);
383 b.write_neg(12, []);
384 });
385 assert_eq!(
386 cbor.decode(),
387 CborValue::Number(Number::Float(Exponential::new(
388 -3,
389 [12_u8][..].into(),
390 true,
391 )))
392 );
393
394 let cbor = CborBuilder::new().write_array([TAG_BIGFLOAT], |b| {
395 b.write_neg(2, []);
396 b.write_pos(0x010203, []);
397 });
398 assert_eq!(
399 cbor.decode(),
400 CborValue::Number(Number::Float(Exponential::new(
401 -3,
402 [1, 2, 3][..].into(),
403 false,
404 )))
405 );
406
407 let cbor = CborBuilder::new().write_array([TAG_BIGFLOAT], |b| {
408 b.write_neg(2, []);
409 b.write_bytes([1, 2, 3].as_ref(), [TAG_BIGNUM_POS]);
410 });
411 assert_eq!(
412 cbor.decode(),
413 CborValue::Number(Number::Float(Exponential::new(
414 -3,
415 [1, 2, 3][..].into(),
416 false,
417 )))
418 );
419
420 let cbor = CborBuilder::new().write_array([TAG_BIGFLOAT], |b| {
421 b.write_neg(2, []);
422 b.write_neg(0x010203, []);
423 });
424 assert_eq!(
425 cbor.decode(),
426 CborValue::Number(Number::Float(Exponential::new(
427 -3,
428 [1, 2, 3][..].into(),
429 true,
430 )))
431 );
432
433 let cbor = CborBuilder::new().write_array([TAG_BIGFLOAT], |b| {
434 b.write_neg(2, []);
435 b.write_bytes([1, 2, 3].as_ref(), [TAG_BIGNUM_NEG]);
436 });
437 assert_eq!(
438 cbor.decode(),
439 CborValue::Number(Number::Float(Exponential::new(
440 -3,
441 [1, 2, 3][..].into(),
442 true,
443 )))
444 );
445
446 let cbor = CborBuilder::new().write_array([TAG_BIGDECIMAL], |b| {
447 b.write_pos(2, []);
448 b.write_pos(0xff01020304, []);
449 });
450 assert_eq!(
451 cbor.decode(),
452 CborValue::Number(Number::Decimal(Exponential::new(
453 2,
454 [255, 1, 2, 3, 4][..].into(),
455 false,
456 )))
457 );
458 }
459}