rmp/decode/ext.rs
1use super::{read_marker, RmpRead, ValueReadError};
2use crate::Marker;
3
4/// Attempts to read exactly 3 bytes from the given reader and interpret them as a fixext1 type
5/// with data attached.
6///
7/// According to the MessagePack specification, a fixext1 stores an integer and a byte array whose
8/// length is 1 byte. Its marker byte is `0xd4`.
9///
10/// Note, that this function copies a byte array from the reader to the output `u8` variable.
11///
12/// # Errors
13///
14/// This function will return `ValueReadError` on any I/O error while reading either the marker or
15/// the data.
16///
17/// # Note
18///
19/// This function will silently retry on every EINTR received from the underlying `Read` until
20/// successful read.
21pub fn read_fixext1<R: RmpRead>(rd: &mut R) -> Result<(i8, u8), ValueReadError<R::Error>> {
22 match read_marker(rd)? {
23 Marker::FixExt1 => {
24 let ty = rd.read_data_i8()?;
25 let data = rd.read_data_u8()?;
26 Ok((ty, data))
27 }
28 marker => Err(ValueReadError::TypeMismatch(marker)),
29 }
30}
31
32/// Attempts to read exactly 4 bytes from the given reader and interpret them as a fixext2 type
33/// with data attached.
34///
35/// According to the MessagePack specification, a fixext2 stores an integer and a byte array whose
36/// length is 2 bytes. Its marker byte is `0xd5`.
37///
38/// Note, that this function copies a byte array from the reader to the output buffer, which is
39/// unlikely if you want zero-copy functionality.
40///
41/// # Errors
42///
43/// This function will return `ValueReadError` on any I/O error while reading either the marker or
44/// the data.
45pub fn read_fixext2<R: RmpRead>(rd: &mut R) -> Result<(i8, [u8; 2]), ValueReadError<R::Error>> {
46 match read_marker(rd)? {
47 Marker::FixExt2 => {
48 let mut buf = [0; 2];
49 read_fixext_data(rd, &mut buf).map(|ty| (ty, buf))
50 }
51 marker => Err(ValueReadError::TypeMismatch(marker)),
52 }
53}
54
55/// Attempts to read exactly 6 bytes from the given reader and interpret them as a fixext4 type
56/// with data attached.
57///
58/// According to the MessagePack specification, a fixext4 stores an integer and a byte array whose
59/// length is 4 bytes. Its marker byte is `0xd6`.
60///
61/// Note, that this function copies a byte array from the reader to the output buffer, which is
62/// unlikely if you want zero-copy functionality.
63///
64/// # Errors
65///
66/// This function will return `ValueReadError` on any I/O error while reading either the marker or
67/// the data.
68pub fn read_fixext4<R: RmpRead>(rd: &mut R) -> Result<(i8, [u8; 4]), ValueReadError<R::Error>> {
69 match read_marker(rd)? {
70 Marker::FixExt4 => {
71 let mut buf = [0; 4];
72 read_fixext_data(rd, &mut buf).map(|ty| (ty, buf))
73 }
74 marker => Err(ValueReadError::TypeMismatch(marker)),
75 }
76}
77
78/// Attempts to read exactly 10 bytes from the given reader and interpret them as a fixext8 type
79/// with data attached.
80///
81/// According to the MessagePack specification, a fixext8 stores an integer and a byte array whose
82/// length is 8 bytes. Its marker byte is `0xd7`.
83///
84/// Note, that this function copies a byte array from the reader to the output buffer, which is
85/// unlikely if you want zero-copy functionality.
86///
87/// # Errors
88///
89/// This function will return `ValueReadError` on any I/O error while reading either the marker or
90/// the data.
91pub fn read_fixext8<R: RmpRead>(rd: &mut R) -> Result<(i8, [u8; 8]), ValueReadError<R::Error>> {
92 match read_marker(rd)? {
93 Marker::FixExt8 => {
94 let mut buf = [0; 8];
95 read_fixext_data(rd, &mut buf).map(|ty| (ty, buf))
96 }
97 marker => Err(ValueReadError::TypeMismatch(marker)),
98 }
99}
100
101/// Attempts to read exactly 18 bytes from the given reader and interpret them as a fixext16 type
102/// with data attached.
103///
104/// According to the MessagePack specification, a fixext16 stores an integer and a byte array whose
105/// length is 16 bytes. Its marker byte is `0xd8`.
106///
107/// Note, that this function copies a byte array from the reader to the output buffer, which is
108/// unlikely if you want zero-copy functionality.
109///
110/// # Errors
111///
112/// This function will return `ValueReadError` on any I/O error while reading either the marker or
113/// the data.
114pub fn read_fixext16<R: RmpRead>(rd: &mut R) -> Result<(i8, [u8; 16]), ValueReadError<R::Error>> {
115 match read_marker(rd)? {
116 Marker::FixExt16 => {
117 let mut buf = [0; 16];
118 read_fixext_data(rd, &mut buf).map(|ty| (ty, buf))
119 }
120 marker => Err(ValueReadError::TypeMismatch(marker)),
121 }
122}
123
124fn read_fixext_data<R: RmpRead>(rd: &mut R, buf: &mut [u8]) -> Result<i8, ValueReadError<R::Error>> {
125 let id = rd.read_data_i8()?;
126 match rd.read_exact_buf(buf) {
127 Ok(()) => Ok(id),
128 Err(err) => Err(ValueReadError::InvalidDataRead(err)),
129 }
130}
131
132/// Extension type meta information.
133///
134/// Extension represents a tuple of type information and a byte array where type information is an
135/// integer whose meaning is defined by applications.
136///
137/// Applications can assign 0 to 127 to store application-specific type information.
138///
139/// # Note
140///
141/// MessagePack reserves -1 to -128 for future extension to add predefined types which will be
142/// described in separated documents.
143#[derive(Debug, PartialEq)]
144pub struct ExtMeta {
145 /// Type information.
146 pub typeid: i8,
147 /// Byte array size.
148 pub size: u32,
149}
150
151pub fn read_ext_meta<R: RmpRead>(rd: &mut R) -> Result<ExtMeta, ValueReadError<R::Error>> {
152 let size = match read_marker(rd)? {
153 Marker::FixExt1 => 1,
154 Marker::FixExt2 => 2,
155 Marker::FixExt4 => 4,
156 Marker::FixExt8 => 8,
157 Marker::FixExt16 => 16,
158 Marker::Ext8 => u32::from(rd.read_data_u8()?),
159 Marker::Ext16 => u32::from(rd.read_data_u16()?),
160 Marker::Ext32 => rd.read_data_u32()?,
161 marker => return Err(ValueReadError::TypeMismatch(marker)),
162 };
163
164 let ty = rd.read_data_i8()?;
165 let meta = ExtMeta { typeid: ty, size };
166
167 Ok(meta)
168}