write_into/
plain.rs

1use super::{write_into, WriteInto};
2use std::io;
3use std::mem::size_of;
4use std::slice::from_raw_parts;
5
6/// Used to write values as they are represented in memory.
7///
8/// # Examples
9///
10/// Writing struct into a sink.
11///
12/// ```
13/// use write_into::{Plain, write_into};
14///
15/// struct Rgba {
16///     r: u8,
17///     g: u8,
18///     b: u8,
19///     a: u8,
20/// }
21///
22/// let color = Rgba { r: 0x18, g: 0x18, b: 0x18, a: 0xFF };
23/// let mut buffer = Vec::new();
24/// write_into(&mut buffer, Plain(&color)).unwrap();
25/// assert_eq!(&buffer, &[0x18, 0x18, 0x18, 0xFF]);
26/// ```
27///
28/// Writing array into a sink.
29///
30/// ```
31/// use write_into::{Plain, write_into};
32///
33/// let bytes: &[u8; 4] = b"\0asm";
34/// let mut buffer = Vec::new();
35/// write_into(&mut buffer, Plain(bytes)).unwrap();
36/// assert_eq!(&buffer, b"\0asm");
37/// ```
38///
39/// Writing slice into a sink (the crate also provides implementation for [`Plain<&str>`]).
40///
41/// ```
42/// use write_into::{Plain, write_into};
43///
44/// let bytes: &[u8] = b"([Ljava/lang/String;)V";
45/// let mut buffer = Vec::new();
46/// write_into(&mut buffer, Plain(bytes)).unwrap();
47/// assert_eq!(&buffer, b"([Ljava/lang/String;)V");
48/// ```
49pub struct Plain<T>(pub T);
50
51/// Transmutes arbitrary value into a byte slice.
52impl<T> WriteInto for Plain<&T> {
53    type Output = ();
54
55    fn write_into(self, sink: &mut impl io::Write) -> io::Result<Self::Output> {
56        // SAFETY:
57        // - The slice points to a memory occupied by the data.
58        // - The data is immutably borrowed.
59        let bytes = unsafe {
60            let data = self.0 as *const T as *const u8;
61            from_raw_parts(data, size_of::<T>())
62        };
63
64        sink.write_all(&bytes)?;
65        Ok(())
66    }
67}
68
69impl<T> WriteInto for &Plain<&T> {
70    type Output = ();
71
72    fn write_into(self, sink: &mut impl io::Write) -> io::Result<Self::Output> {
73        write_into(sink, Plain(self.0))
74    }
75}
76
77/// Transmutes arbitrary slice into a byte slice.
78impl<T> WriteInto for Plain<&[T]> {
79    type Output = ();
80
81    fn write_into(self, sink: &mut impl io::Write) -> io::Result<Self::Output> {
82        // SAFETY:
83        // - The slice points to a memory occupied by the data.
84        // - The data is immutably borrowed.
85        let bytes = unsafe {
86            let data = self.0 as *const [T] as *const u8;
87            from_raw_parts(data, self.0.len() * size_of::<T>())
88        };
89
90        sink.write_all(&bytes)?;
91        Ok(())
92    }
93}
94
95impl<T> WriteInto for &Plain<&[T]> {
96    type Output = ();
97
98    fn write_into(self, sink: &mut impl io::Write) -> io::Result<Self::Output> {
99        write_into(sink, Plain(self.0))
100    }
101}
102
103impl WriteInto for Plain<&str> {
104    type Output = ();
105
106    fn write_into(self, sink: &mut impl io::Write) -> io::Result<Self::Output> {
107        sink.write_all(self.0.as_bytes())?;
108        Ok(())
109    }
110}
111
112impl WriteInto for &Plain<&str> {
113    type Output = ();
114
115    fn write_into(self, sink: &mut impl io::Write) -> io::Result<Self::Output> {
116        write_into(sink, Plain(self.0))
117    }
118}
119
120macro_rules! impl_write_into {
121    ($($primitive:ty)*) => {
122        $(
123            impl WriteInto for Plain<$primitive> {
124                type Output = ();
125
126                fn write_into(self, sink: &mut impl io::Write) -> io::Result<Self::Output> {
127                    write_into(sink, Plain(&self.0))
128                }
129            }
130
131            impl WriteInto for &Plain<$primitive> {
132                type Output = ();
133
134                fn write_into(self, sink: &mut impl io::Write) -> io::Result<Self::Output> {
135                    write_into(sink, Plain(&self.0))
136                }
137            }
138        )*
139    };
140}
141
142impl_write_into! {
143    i8 i16 i32 i64 i128 isize
144    u8 u16 u32 u64 u128 usize
145    bool char f32 f64
146}
147
148#[cfg(test)]
149mod tests {
150    use super::super::*;
151    use super::*;
152
153    #[test]
154    fn write_u8() {
155        let mut buffer = Vec::new();
156        write_into(&mut buffer, Plain(&0x7Fu8)).unwrap();
157        assert_eq!(&buffer, &[0x7F]);
158    }
159
160    #[test]
161    fn write_str() {
162        let bytes = "([Ljava/lang/String;)V";
163        let mut buffer = Vec::new();
164        write_into(&mut buffer, Plain(bytes)).unwrap();
165        assert_eq!(&buffer, b"([Ljava/lang/String;)V");
166    }
167
168    #[test]
169    fn write_slice_of_arrays() {
170        let bytes: &[[u8; 2]] = &[[0x01, 0x02], [0x03, 0x04]];
171        let mut buffer = Vec::new();
172        write_into(&mut buffer, Plain(bytes)).unwrap();
173        assert_eq!(&buffer, &[0x01, 0x02, 0x03, 0x04]);
174    }
175}