codec_cbor/
encode_dag_cbor.rs1use crate::{CborError, CborValue, MAX_DAG_CBOR_INPUT_LEN, MAX_NESTING_DEPTH};
6
7const MT_UINT: u8 = 0;
8const MT_NEGINT: u8 = 1;
9const MT_BYTES: u8 = 2;
10const MT_STRING: u8 = 3;
11const MT_ARRAY: u8 = 4;
12const MT_MAP: u8 = 5;
13
14pub fn encode_dag_cbor(value: &CborValue) -> Result<Vec<u8>, CborError> {
24 let mut out = Vec::new();
25 encode_value(value, &mut out, 0)?;
26 Ok(out)
27}
28
29fn encode_value(v: &CborValue, out: &mut Vec<u8>, depth: usize) -> Result<(), CborError> {
30 match v {
31 CborValue::Null => push_byte(out, 0xf6)?,
32 CborValue::Bool(false) => push_byte(out, 0xf4)?,
33 CborValue::Bool(true) => push_byte(out, 0xf5)?,
34
35 CborValue::Int(n) => {
36 if *n >= 0 {
37 write_header(MT_UINT, n.unsigned_abs(), out)?;
38 } else {
39 write_header(MT_NEGINT, n.unsigned_abs() - 1, out)?;
40 }
41 }
42
43 CborValue::Bytes(b) => {
44 write_header(MT_BYTES, len_as_u64(b.len())?, out)?;
45 extend_bytes(out, b)?;
46 }
47
48 CborValue::String(s) => {
49 let bytes = s.as_bytes();
50 write_header(MT_STRING, len_as_u64(bytes.len())?, out)?;
51 extend_bytes(out, bytes)?;
52 }
53
54 CborValue::Array(arr) => {
55 let child_depth = descend(depth)?;
56 ensure_minimum_encoded_len(arr.len(), 1)?;
57 write_header(MT_ARRAY, len_as_u64(arr.len())?, out)?;
58 for v in arr {
59 encode_value(v, out, child_depth)?;
60 }
61 }
62
63 CborValue::Map(entries) => {
64 let child_depth = descend(depth)?;
65 ensure_minimum_encoded_len(entries.len(), 2)?;
66 let mut sorted: Vec<(&String, &CborValue)> =
70 entries.iter().map(|(key, value)| (key, value)).collect();
71 sorted.sort_by(|(ka, _), (kb, _)| {
72 ka.len()
73 .cmp(&kb.len())
74 .then_with(|| ka.as_bytes().cmp(kb.as_bytes()))
75 });
76
77 if sorted
78 .windows(2)
79 .any(|pair| pair[0].0.as_bytes() == pair[1].0.as_bytes())
80 {
81 return Err(CborError::DuplicateMapKey);
82 }
83
84 write_header(MT_MAP, len_as_u64(sorted.len())?, out)?;
85
86 for (k, v) in sorted {
87 let kb = k.as_bytes();
88 write_header(MT_STRING, len_as_u64(kb.len())?, out)?;
89 extend_bytes(out, kb)?;
90 encode_value(v, out, child_depth)?;
91 }
92 }
93 }
94 Ok(())
95}
96
97fn len_as_u64(len: usize) -> Result<u64, CborError> {
103 u64::try_from(len).map_err(|_| CborError::LengthTooLarge)
104}
105
106fn write_header(mt: u8, value: u64, out: &mut Vec<u8>) -> Result<(), CborError> {
113 let be = value.to_be_bytes();
114 let head = mt << 5;
115 if value < 24 {
116 push_byte(out, head | be[7])?;
118 } else if value < 0x100 {
119 push_byte(out, head | 24)?;
120 extend_bytes(out, &be[7..8])?;
121 } else if value < 0x1_0000 {
122 push_byte(out, head | 25)?;
123 extend_bytes(out, &be[6..8])?;
124 } else if value < 0x1_0000_0000 {
125 push_byte(out, head | 26)?;
126 extend_bytes(out, &be[4..8])?;
127 } else {
128 push_byte(out, head | 27)?;
129 extend_bytes(out, &be)?;
130 }
131 Ok(())
132}
133
134fn push_byte(out: &mut Vec<u8>, byte: u8) -> Result<(), CborError> {
135 let next_len = out.len().checked_add(1).ok_or(CborError::OffsetOverflow)?;
136 if next_len > MAX_DAG_CBOR_INPUT_LEN {
137 return Err(CborError::OutputTooLarge);
138 }
139 out.push(byte);
140 Ok(())
141}
142
143fn extend_bytes(out: &mut Vec<u8>, bytes: &[u8]) -> Result<(), CborError> {
144 let next_len = out
145 .len()
146 .checked_add(bytes.len())
147 .ok_or(CborError::OffsetOverflow)?;
148 if next_len > MAX_DAG_CBOR_INPUT_LEN {
149 return Err(CborError::OutputTooLarge);
150 }
151 out.extend_from_slice(bytes);
152 Ok(())
153}
154
155fn descend(depth: usize) -> Result<usize, CborError> {
156 let next = depth.checked_add(1).ok_or(CborError::OffsetOverflow)?;
157 if next > MAX_NESTING_DEPTH {
158 return Err(CborError::DepthExceeded);
159 }
160 Ok(next)
161}
162
163fn ensure_minimum_encoded_len(count: usize, min_element_len: usize) -> Result<(), CborError> {
164 let minimum = count
165 .checked_mul(min_element_len)
166 .ok_or(CborError::OffsetOverflow)?;
167 if minimum > MAX_DAG_CBOR_INPUT_LEN {
168 return Err(CborError::OutputTooLarge);
169 }
170 Ok(())
171}