-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathserialize.rs
More file actions
168 lines (148 loc) · 4.74 KB
/
Copy pathserialize.rs
File metadata and controls
168 lines (148 loc) · 4.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#![cfg_attr(test, allow(clippy::unwrap_used))]
use crate::error::BinaryError;
use serde::Serialize;
use std::io::Write;
/// Serialise a value into a vector of bytes using canonical CBOR semantics.
///
/// # Errors
///
/// Returns [`BinaryError::Serialization`] if the value cannot be serialized to CBOR.
pub fn serialize<T: Serialize>(value: &T) -> Result<Vec<u8>, BinaryError> {
let mut buf = Vec::new();
ciborium::into_writer(value, &mut buf)?;
Ok(buf)
}
/// Serialise a value and return an owned byte vector (strict variant).
///
/// # Errors
///
/// Returns [`BinaryError::Serialization`] if the value cannot be serialized to CBOR.
pub fn serialize_strict<T: Serialize>(value: &T) -> Result<Vec<u8>, BinaryError> {
serialize(value)
}
/// Serialise a value using an existing IO writer.
///
/// # Errors
///
/// Returns [`BinaryError::Serialization`] if:
/// - The value cannot be serialized to CBOR
/// - Writing to the output fails
pub fn serialize_into_writer<T, W>(value: &T, writer: W) -> Result<(), BinaryError>
where
T: Serialize,
W: Write,
{
ciborium::into_writer(value, writer)?;
Ok(())
}
/// Serialise into an existing byte buffer, reusing its allocation.
///
/// # Errors
///
/// Returns [`BinaryError::Serialization`] if the value cannot be serialized to CBOR.
pub fn serialize_into_vec<T: Serialize>(
value: &T,
buffer: &mut Vec<u8>,
) -> Result<(), BinaryError> {
buffer.clear();
ciborium::into_writer(value, buffer)?;
Ok(())
}
/// Serialise into a vector after reserving the provided capacity hint.
///
/// # Errors
///
/// Returns [`BinaryError::Serialization`] if the value cannot be serialized to CBOR.
pub fn serialize_with_capacity<T: Serialize>(
value: &T,
capacity_hint: usize,
) -> Result<Vec<u8>, BinaryError> {
let mut buffer = Vec::with_capacity(capacity_hint);
serialize_into_vec(value, &mut buffer)?;
Ok(buffer)
}
/// Produce a nested CBOR encoding using the semantic tag 24.
///
/// # Errors
///
/// Returns [`BinaryError::Serialization`] if the value cannot be serialized to CBOR.
pub fn encode_nested_cbor<T: Serialize>(value: &T) -> Result<Vec<u8>, BinaryError> {
let inner = serialize(value)?;
encode_nested_cbor_bytes(&inner)
}
/// Wrap an existing CBOR payload with the semantic tag 24.
///
/// # Errors
///
/// Returns [`BinaryError::Serialization`] if the tagged value cannot be serialized to CBOR.
pub fn encode_nested_cbor_bytes(bytes: &[u8]) -> Result<Vec<u8>, BinaryError> {
use ciborium::value::Value;
let tagged = Value::Tag(24, Box::new(Value::Bytes(bytes.to_vec())));
let mut buf = Vec::new();
ciborium::into_writer(&tagged, &mut buf)?;
Ok(buf)
}
#[cfg(test)]
mod tests {
use super::*;
use serde::Deserialize;
use serde_bytes::ByteBuf;
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
struct Sample {
label: String,
value: u32,
}
#[test]
fn serialises_roundtrip() {
let sample = Sample {
label: "abc".into(),
value: 42,
};
let bytes = serialize(&sample).unwrap();
let decoded: Sample = ciborium::from_reader(&bytes[..]).unwrap();
assert_eq!(sample, decoded);
}
#[test]
fn encode_nested_wraps_tag() {
use ciborium::value::Value;
let payload = ByteBuf::from(vec![0x01, 0x02]);
let tagged = encode_nested_cbor(&payload).unwrap();
let decoded: Value = ciborium::from_reader(&tagged[..]).unwrap();
let boxed_value = match decoded {
Value::Tag(24, boxed_value) => Ok(boxed_value),
_ => Err(()),
}
.expect("expected Tag(24) wrapper");
let bytes = match *boxed_value {
Value::Bytes(bytes) => Ok(bytes),
_ => Err(()),
}
.expect("expected byte string in Tag(24) payload");
let mut expected = Vec::new();
ciborium::into_writer(&payload, &mut expected).unwrap();
assert_eq!(bytes, expected);
}
#[test]
fn reuse_buffer_serialisation() {
let sample = Sample {
label: "reuse".into(),
value: 7,
};
let mut buffer = vec![0xde, 0xad, 0xbe, 0xef];
serialize_into_vec(&sample, &mut buffer).unwrap();
assert_ne!(buffer, vec![0xde, 0xad, 0xbe, 0xef]);
let decoded: Sample = ciborium::from_reader(&buffer[..]).unwrap();
assert_eq!(decoded, sample);
}
#[test]
fn capacity_hint_serialises() {
let sample = Sample {
label: "hint".into(),
value: 99,
};
let encoded = serialize_with_capacity(&sample, 128).unwrap();
let decoded: Sample = ciborium::from_reader(&encoded[..]).unwrap();
assert_eq!(decoded, sample);
assert!(encoded.capacity() >= 128);
}
}