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}