rmp/decode/
ext.rs

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