1use alloc::boxed::Box;
2use alloc::string::String;
3use alloc::vec::Vec;
4
5use crate::error::AccessError;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum CborValue {
9 Unsigned(u64),
10 Negative(i64),
11 Bytes(Vec<u8>),
12 Text(String),
13 Array(Vec<CborValue>),
14 Map(Vec<(CborValue, CborValue)>),
15 Tag(u64, Box<CborValue>),
16 Bool(bool),
17 Null,
18}
19
20impl CborValue {
21 pub fn as_unsigned(&self) -> Option<u64> {
22 match self {
23 Self::Unsigned(value) => Some(*value),
24 _ => None,
25 }
26 }
27
28 pub fn as_negative(&self) -> Option<i64> {
29 match self {
30 Self::Negative(value) => Some(*value),
31 _ => None,
32 }
33 }
34
35 pub fn as_bytes(&self) -> Option<&[u8]> {
36 match self {
37 Self::Bytes(value) => Some(value.as_slice()),
38 _ => None,
39 }
40 }
41
42 pub fn as_text(&self) -> Option<&str> {
43 match self {
44 Self::Text(value) => Some(value.as_str()),
45 _ => None,
46 }
47 }
48
49 pub fn as_array(&self) -> Option<&[CborValue]> {
50 match self {
51 Self::Array(values) => Some(values.as_slice()),
52 _ => None,
53 }
54 }
55
56 pub fn as_map(&self) -> Option<&[(CborValue, CborValue)]> {
57 match self {
58 Self::Map(values) => Some(values.as_slice()),
59 _ => None,
60 }
61 }
62
63 pub fn as_tag(&self) -> Option<(u64, &CborValue)> {
64 match self {
65 Self::Tag(tag, value) => Some((*tag, value.as_ref())),
66 _ => None,
67 }
68 }
69
70 pub fn as_bool(&self) -> Option<bool> {
71 match self {
72 Self::Bool(value) => Some(*value),
73 _ => None,
74 }
75 }
76
77 pub fn is_null(&self) -> bool {
78 matches!(self, Self::Null)
79 }
80
81 pub fn get(&self, key: &str) -> Option<&CborValue> {
82 match self {
83 Self::Map(entries) => entries
84 .iter()
85 .find_map(|(entry_key, value)| match entry_key {
86 Self::Text(text) if text == key => Some(value),
87 _ => None,
88 }),
89 _ => None,
90 }
91 }
92
93 pub fn required_text(&self, key: &str) -> Result<&str, AccessError> {
94 self.required_value(key, CborValue::as_text, "text")
95 }
96
97 pub fn required_bytes(&self, key: &str) -> Result<&[u8], AccessError> {
98 self.required_value(key, CborValue::as_bytes, "bytes")
99 }
100
101 pub fn required_unsigned(&self, key: &str) -> Result<u64, AccessError> {
102 self.required_value(key, CborValue::as_unsigned, "unsigned")
103 }
104
105 pub fn required_negative(&self, key: &str) -> Result<i64, AccessError> {
106 self.required_value(key, CborValue::as_negative, "negative")
107 }
108
109 pub fn required_bool(&self, key: &str) -> Result<bool, AccessError> {
110 self.required_value(key, CborValue::as_bool, "bool")
111 }
112
113 pub fn required_array(&self, key: &str) -> Result<&[CborValue], AccessError> {
114 self.required_value(key, CborValue::as_array, "array")
115 }
116
117 pub fn required_map(&self, key: &str) -> Result<&[(CborValue, CborValue)], AccessError> {
118 self.required_value(key, CborValue::as_map, "map")
119 }
120
121 pub fn required_tag(&self, key: &str) -> Result<(u64, &CborValue), AccessError> {
122 self.required_value(key, CborValue::as_tag, "tag")
123 }
124
125 fn required_value<'a, T>(
126 &'a self,
127 key: &str,
128 accessor: impl FnOnce(&'a CborValue) -> Option<T>,
129 expected: &'static str,
130 ) -> Result<T, AccessError> {
131 let value = self.object_field(key)?;
132 accessor(value).ok_or_else(|| AccessError::TypeMismatch {
133 field: key.into(),
134 expected,
135 })
136 }
137
138 fn object_field(&self, key: &str) -> Result<&CborValue, AccessError> {
139 match self {
140 Self::Map(_) => self
141 .get(key)
142 .ok_or_else(|| AccessError::MissingField(key.into())),
143 _ => Err(AccessError::NotAMap),
144 }
145 }
146}