1use facet::Facet;
2use facet_core::{Def, ScalarType, StructKind, Type, UserType};
3use facet_reflect::Peek;
4
5use crate::encode;
6use crate::error::CborError;
7
8pub fn to_vec<'a, T: Facet<'a>>(value: &T) -> Result<Vec<u8>, CborError> {
10 let peek = Peek::new(value);
11 let mut out = Vec::new();
12 serialize_peek(peek, &mut out)?;
13 Ok(out)
14}
15
16pub fn serialize_peek(peek: Peek<'_, '_>, out: &mut Vec<u8>) -> Result<(), CborError> {
18 let peek = peek.innermost_peek();
20
21 if let Some(scalar_type) = peek.scalar_type() {
23 return serialize_scalar(peek, scalar_type, out);
24 }
25
26 match peek.shape().def {
29 Def::Option(_) => {
30 let opt = peek
31 .into_option()
32 .map_err(|e| CborError::ReflectError(e.to_string()))?;
33 return match opt.value() {
34 Some(inner) => serialize_peek(inner, out),
35 None => {
36 encode::write_null(out);
37 Ok(())
38 }
39 };
40 }
41 Def::List(list_def) => {
42 if list_def.t().is_type::<u8>() {
44 let list = peek
45 .into_list()
46 .map_err(|e| CborError::ReflectError(e.to_string()))?;
47 let len = list.len();
48 let mut bytes = Vec::with_capacity(len);
49 for i in 0..len {
50 let elem = list.get(i).ok_or_else(|| {
51 CborError::ReflectError("list index out of bounds".into())
52 })?;
53 let byte = elem
54 .get::<u8>()
55 .map_err(|e| CborError::ReflectError(e.to_string()))?;
56 bytes.push(*byte);
57 }
58 encode::write_bytes(out, &bytes);
59 } else {
60 let list = peek
61 .into_list()
62 .map_err(|e| CborError::ReflectError(e.to_string()))?;
63 let len = list.len();
64 encode::write_array_header(out, len as u64);
65 for elem in list.iter() {
66 serialize_peek(elem, out)?;
67 }
68 }
69 return Ok(());
70 }
71 Def::Array(_) | Def::Slice(_) => {
72 let list_like = peek
73 .into_list_like()
74 .map_err(|e| CborError::ReflectError(e.to_string()))?;
75 let len = list_like.len();
76 encode::write_array_header(out, len as u64);
77 for elem in list_like.iter() {
78 serialize_peek(elem, out)?;
79 }
80 return Ok(());
81 }
82 Def::Map(_) => {
83 let map = peek
84 .into_map()
85 .map_err(|e| CborError::ReflectError(e.to_string()))?;
86 encode::write_map_header(out, map.len() as u64);
87 for (key, value) in map.iter() {
88 serialize_peek(key, out)?;
89 serialize_peek(value, out)?;
90 }
91 return Ok(());
92 }
93 Def::Set(_) => {
94 let set = peek
95 .into_set()
96 .map_err(|e| CborError::ReflectError(e.to_string()))?;
97 encode::write_array_header(out, set.len() as u64);
98 for elem in set.iter() {
99 serialize_peek(elem, out)?;
100 }
101 return Ok(());
102 }
103 Def::Pointer(_) => {
104 let ptr = peek
105 .into_pointer()
106 .map_err(|e| CborError::ReflectError(e.to_string()))?;
107 return match ptr.borrow_inner() {
108 Some(inner) => serialize_peek(inner, out),
109 None => {
110 encode::write_null(out);
111 Ok(())
112 }
113 };
114 }
115 _ => {}
116 }
117
118 match peek.shape().ty {
120 Type::User(UserType::Struct(struct_type)) => match struct_type.kind {
121 StructKind::Struct => {
122 let ps = peek
123 .into_struct()
124 .map_err(|e| CborError::ReflectError(e.to_string()))?;
125 encode::write_map_header(out, ps.field_count() as u64);
126 for i in 0..ps.field_count() {
127 let field = &struct_type.fields[i];
128 encode::write_text(out, field.name);
129 let field_peek = ps
130 .field(i)
131 .map_err(|e| CborError::ReflectError(e.to_string()))?;
132 serialize_peek(field_peek, out)?;
133 }
134 return Ok(());
135 }
136 StructKind::TupleStruct | StructKind::Tuple => {
137 let ps = peek
138 .into_struct()
139 .map_err(|e| CborError::ReflectError(e.to_string()))?;
140 encode::write_array_header(out, ps.field_count() as u64);
141 for i in 0..ps.field_count() {
142 let field_peek = ps
143 .field(i)
144 .map_err(|e| CborError::ReflectError(e.to_string()))?;
145 serialize_peek(field_peek, out)?;
146 }
147 return Ok(());
148 }
149 StructKind::Unit => {
150 encode::write_null(out);
151 return Ok(());
152 }
153 },
154 Type::User(UserType::Enum(_)) => {
155 let pe = peek
156 .into_enum()
157 .map_err(|e| CborError::ReflectError(e.to_string()))?;
158 let variant = pe
159 .active_variant()
160 .map_err(|e| CborError::ReflectError(e.to_string()))?;
161
162 let effective_name = variant.rename.unwrap_or(variant.name);
163
164 if let Some(tag_key) = peek.shape().tag {
165 return serialize_enum_internally_tagged(pe, variant, effective_name, tag_key, out);
167 }
168
169 encode::write_map_header(out, 1);
171 encode::write_text(out, effective_name);
172
173 match variant.data.kind {
174 StructKind::Unit => {
175 encode::write_null(out);
176 }
177 StructKind::TupleStruct => {
178 if variant.data.fields.len() == 1 {
180 let field_peek = pe
181 .field(0)
182 .map_err(|e| CborError::ReflectError(e.to_string()))?
183 .ok_or_else(|| {
184 CborError::ReflectError("missing newtype variant field".into())
185 })?;
186 serialize_peek(field_peek, out)?;
187 } else {
188 encode::write_array_header(out, variant.data.fields.len() as u64);
189 for i in 0..variant.data.fields.len() {
190 let field_peek = pe
191 .field(i)
192 .map_err(|e| CborError::ReflectError(e.to_string()))?
193 .ok_or_else(|| {
194 CborError::ReflectError("missing tuple variant field".into())
195 })?;
196 serialize_peek(field_peek, out)?;
197 }
198 }
199 }
200 StructKind::Tuple => {
201 encode::write_array_header(out, variant.data.fields.len() as u64);
202 for i in 0..variant.data.fields.len() {
203 let field_peek = pe
204 .field(i)
205 .map_err(|e| CborError::ReflectError(e.to_string()))?
206 .ok_or_else(|| {
207 CborError::ReflectError("missing tuple variant field".into())
208 })?;
209 serialize_peek(field_peek, out)?;
210 }
211 }
212 StructKind::Struct => {
213 encode::write_map_header(out, variant.data.fields.len() as u64);
214 for i in 0..variant.data.fields.len() {
215 let field = &variant.data.fields[i];
216 encode::write_text(out, field.name);
217 let field_peek = pe
218 .field(i)
219 .map_err(|e| CborError::ReflectError(e.to_string()))?
220 .ok_or_else(|| {
221 CborError::ReflectError("missing struct variant field".into())
222 })?;
223 serialize_peek(field_peek, out)?;
224 }
225 }
226 }
227 return Ok(());
228 }
229 _ => {}
230 }
231
232 Err(CborError::UnsupportedType(format!("{}", peek.shape())))
233}
234
235fn serialize_scalar(
236 peek: Peek<'_, '_>,
237 scalar_type: ScalarType,
238 out: &mut Vec<u8>,
239) -> Result<(), CborError> {
240 match scalar_type {
241 ScalarType::Unit => {
242 encode::write_null(out);
243 }
244 ScalarType::Bool => {
245 let v = peek
246 .get::<bool>()
247 .map_err(|e| CborError::ReflectError(e.to_string()))?;
248 encode::write_bool(out, *v);
249 }
250 ScalarType::Char => {
251 let v = peek
252 .get::<char>()
253 .map_err(|e| CborError::ReflectError(e.to_string()))?;
254 let mut buf = [0u8; 4];
255 let s = v.encode_utf8(&mut buf);
256 encode::write_text(out, s);
257 }
258 ScalarType::U8 => {
259 let v = peek
260 .get::<u8>()
261 .map_err(|e| CborError::ReflectError(e.to_string()))?;
262 encode::write_uint(out, *v as u64);
263 }
264 ScalarType::U16 => {
265 let v = peek
266 .get::<u16>()
267 .map_err(|e| CborError::ReflectError(e.to_string()))?;
268 encode::write_uint(out, *v as u64);
269 }
270 ScalarType::U32 => {
271 let v = peek
272 .get::<u32>()
273 .map_err(|e| CborError::ReflectError(e.to_string()))?;
274 encode::write_uint(out, *v as u64);
275 }
276 ScalarType::U64 => {
277 let v = peek
278 .get::<u64>()
279 .map_err(|e| CborError::ReflectError(e.to_string()))?;
280 encode::write_uint(out, *v);
281 }
282 ScalarType::U128 => {
283 let v = peek
284 .get::<u128>()
285 .map_err(|e| CborError::ReflectError(e.to_string()))?;
286 if *v <= u64::MAX as u128 {
288 encode::write_uint(out, *v as u64);
289 } else {
290 out.push(0xc2);
292 let bytes = v.to_be_bytes();
293 let start = bytes.iter().position(|&b| b != 0).unwrap_or(15);
295 encode::write_bytes(out, &bytes[start..]);
296 }
297 }
298 ScalarType::USize => {
299 let v = peek
300 .get::<usize>()
301 .map_err(|e| CborError::ReflectError(e.to_string()))?;
302 encode::write_uint(out, *v as u64);
303 }
304 ScalarType::I8 => {
305 let v = peek
306 .get::<i8>()
307 .map_err(|e| CborError::ReflectError(e.to_string()))?;
308 write_signed(out, *v as i64);
309 }
310 ScalarType::I16 => {
311 let v = peek
312 .get::<i16>()
313 .map_err(|e| CborError::ReflectError(e.to_string()))?;
314 write_signed(out, *v as i64);
315 }
316 ScalarType::I32 => {
317 let v = peek
318 .get::<i32>()
319 .map_err(|e| CborError::ReflectError(e.to_string()))?;
320 write_signed(out, *v as i64);
321 }
322 ScalarType::I64 => {
323 let v = peek
324 .get::<i64>()
325 .map_err(|e| CborError::ReflectError(e.to_string()))?;
326 write_signed(out, *v);
327 }
328 ScalarType::I128 => {
329 let v = peek
330 .get::<i128>()
331 .map_err(|e| CborError::ReflectError(e.to_string()))?;
332 if *v >= 0 {
333 if *v <= u64::MAX as i128 {
334 encode::write_uint(out, *v as u64);
335 } else {
336 out.push(0xc2);
338 let bytes = (*v as u128).to_be_bytes();
339 let start = bytes.iter().position(|&b| b != 0).unwrap_or(15);
340 encode::write_bytes(out, &bytes[start..]);
341 }
342 } else {
343 let abs_minus_one = (-1i128 - *v) as u128;
345 if abs_minus_one <= u64::MAX as u128 {
346 encode::write_neg(out, abs_minus_one as u64);
347 } else {
348 out.push(0xc3);
350 let bytes = abs_minus_one.to_be_bytes();
351 let start = bytes.iter().position(|&b| b != 0).unwrap_or(15);
352 encode::write_bytes(out, &bytes[start..]);
353 }
354 }
355 }
356 ScalarType::ISize => {
357 let v = peek
358 .get::<isize>()
359 .map_err(|e| CborError::ReflectError(e.to_string()))?;
360 write_signed(out, *v as i64);
361 }
362 ScalarType::F32 => {
363 let v = peek
364 .get::<f32>()
365 .map_err(|e| CborError::ReflectError(e.to_string()))?;
366 encode::write_f32(out, *v);
367 }
368 ScalarType::F64 => {
369 let v = peek
370 .get::<f64>()
371 .map_err(|e| CborError::ReflectError(e.to_string()))?;
372 encode::write_f64(out, *v);
373 }
374 ScalarType::Str | ScalarType::String | ScalarType::CowStr => {
375 let s = peek
376 .as_str()
377 .ok_or_else(|| CborError::ReflectError("failed to extract string value".into()))?;
378 encode::write_text(out, s);
379 }
380 _ => {
381 return Err(CborError::UnsupportedType(format!(
382 "scalar type {scalar_type:?}"
383 )));
384 }
385 }
386 Ok(())
387}
388
389fn serialize_enum_internally_tagged(
396 pe: facet_reflect::PeekEnum<'_, '_>,
397 variant: &facet_core::Variant,
398 effective_name: &str,
399 tag_key: &str,
400 out: &mut Vec<u8>,
401) -> Result<(), CborError> {
402 match variant.data.kind {
403 StructKind::Unit => {
404 encode::write_text(out, effective_name);
406 }
407 StructKind::Struct => {
408 let field_count = variant.data.fields.len();
410 encode::write_map_header(out, (field_count + 1) as u64);
411 encode::write_text(out, tag_key);
413 encode::write_text(out, effective_name);
414 for i in 0..field_count {
416 let field = &variant.data.fields[i];
417 encode::write_text(out, field.name);
418 let field_peek = pe
419 .field(i)
420 .map_err(|e| CborError::ReflectError(e.to_string()))?
421 .ok_or_else(|| {
422 CborError::ReflectError("missing struct variant field".into())
423 })?;
424 serialize_peek(field_peek, out)?;
425 }
426 }
427 StructKind::TupleStruct | StructKind::Tuple => {
428 return Err(CborError::UnsupportedType(format!(
429 "internally-tagged enum cannot have tuple variant '{}'",
430 variant.name
431 )));
432 }
433 }
434 Ok(())
435}
436
437fn write_signed(out: &mut Vec<u8>, v: i64) {
438 if v >= 0 {
439 encode::write_uint(out, v as u64);
440 } else {
441 encode::write_neg(out, (-1i64 - v) as u64);
443 }
444}