ignite_rs/protocol/
data_types.rs

1use std::io::{Read, Write};
2
3use crate::error::{IgniteError, IgniteResult};
4use crate::protocol::*;
5use crate::protocol::{read_u8, TypeCode};
6
7use crate::{Enum, ReadableType, WritableType};
8use std::io;
9
10/// Ignite's 'char' is a UTF-16 code UNIT, which means its size is 2 bytes.
11/// As Rust's 'char' is a Unicode scalar value (a.k.a UTF-32 code unit) and has 4 bytes,
12/// I don't see how the API should be properly implemented. u16 is used for now
13
14macro_rules! write_type {
15    ($t:ty, $code:path, $write_fn:ident, $size:expr) => {
16        impl WritableType for $t {
17            fn write(&self, writer: &mut dyn Write) -> io::Result<()> {
18                write_u8(writer, $code as u8)?;
19                $write_fn(writer, *self)?;
20                Ok(())
21            }
22
23            fn size(&self) -> usize {
24                $size + 1 // size, type code
25            }
26        }
27    };
28}
29
30write_type!(u8, TypeCode::Byte, write_u8, 1);
31write_type!(u16, TypeCode::Char, write_u16, 2);
32write_type!(i16, TypeCode::Short, write_i16, 2);
33write_type!(i32, TypeCode::Int, write_i32, 4);
34write_type!(i64, TypeCode::Long, write_i64, 8);
35write_type!(f32, TypeCode::Float, write_f32, 4);
36write_type!(f64, TypeCode::Double, write_f64, 8);
37write_type!(bool, TypeCode::Bool, write_bool, 1);
38write_type!(Enum, TypeCode::Enum, write_enum, 8);
39
40impl WritableType for String {
41    fn write(&self, writer: &mut dyn Write) -> io::Result<()> {
42        write_u8(writer, TypeCode::String as u8)?;
43        write_string(writer, self)?;
44        Ok(())
45    }
46
47    fn size(&self) -> usize {
48        self.len() + 1 + 4 // string itself, type code, len
49    }
50}
51
52macro_rules! read_type {
53    ($t:ty, $read_fn:ident) => {
54        impl ReadableType for $t {
55            fn read_unwrapped(
56                type_code: TypeCode,
57                reader: &mut impl Read,
58            ) -> IgniteResult<Option<Self>> {
59                let value: Option<Self> = match type_code {
60                    TypeCode::Null => None,
61                    _ => Some($read_fn(reader)?),
62                };
63                Ok(value)
64            }
65        }
66    };
67}
68
69read_type!(u8, read_u8);
70read_type!(u16, read_u16);
71read_type!(i16, read_i16);
72read_type!(i32, read_i32);
73read_type!(i64, read_i64);
74read_type!(f32, read_f32);
75read_type!(f64, read_f64);
76read_type!(bool, read_bool);
77read_type!(String, read_string);
78read_type!(Enum, read_enum);
79
80macro_rules! write_primitive_arr {
81    ($t:ty, $code:path, $write_fn:ident, $size:expr) => {
82        impl WritableType for Vec<$t> {
83            fn write(&self, writer: &mut dyn Write) -> io::Result<()> {
84                write_u8(writer, $code as u8)?;
85                write_i32(writer, self.len() as i32)?; // length of array
86                for el in self {
87                    $write_fn(writer, *el)?;
88                }
89                Ok(())
90            }
91
92            fn size(&self) -> usize {
93                $size * self.len() + 4 + 1 // size * len, len, type code
94            }
95        }
96    };
97}
98
99write_primitive_arr!(u8, TypeCode::ArrByte, write_u8, 1);
100write_primitive_arr!(i16, TypeCode::ArrShort, write_i16, 2);
101write_primitive_arr!(i32, TypeCode::ArrInt, write_i32, 4);
102write_primitive_arr!(i64, TypeCode::ArrLong, write_i64, 8);
103write_primitive_arr!(f32, TypeCode::ArrFloat, write_f32, 4);
104write_primitive_arr!(f64, TypeCode::ArrDouble, write_f64, 8);
105write_primitive_arr!(bool, TypeCode::ArrBool, write_bool, 1);
106write_primitive_arr!(u16, TypeCode::ArrChar, write_u16, 2);
107
108macro_rules! read_primitive_arr {
109    ($t:ty, $read_fn:ident) => {
110        impl ReadableType for Vec<$t> {
111            fn read_unwrapped(
112                type_code: TypeCode,
113                reader: &mut impl Read,
114            ) -> IgniteResult<Option<Self>> {
115                let value: Option<Self> = match type_code {
116                    TypeCode::Null => None,
117                    _ => Some(read_primitive_arr(reader, $read_fn)?),
118                };
119                Ok(value)
120            }
121        }
122    };
123}
124
125read_primitive_arr!(u8, read_u8);
126read_primitive_arr!(u16, read_u16);
127read_primitive_arr!(i16, read_i16);
128read_primitive_arr!(i32, read_i32);
129read_primitive_arr!(i64, read_i64);
130read_primitive_arr!(f32, read_f32);
131read_primitive_arr!(f64, read_f64);
132read_primitive_arr!(bool, read_bool);
133
134// pack all vectors as object array
135impl<T: WritableType + ReadableType> WritableType for Vec<Option<T>> {
136    fn write(&self, writer: &mut dyn Write) -> io::Result<()> {
137        write_u8(writer, TypeCode::ArrObj as u8)?;
138        write_i32(writer, -1)?; // typeid. always -1
139        write_i32(writer, self.len() as i32)?; // length of array
140        for item in self {
141            match item {
142                None => write_u8(writer, TypeCode::Null as u8)?,
143                Some(value) => value.write(writer)?,
144            }
145        }
146        Ok(())
147    }
148
149    fn size(&self) -> usize {
150        let mut items_size: usize = 0;
151        for item in self {
152            match item {
153                None => items_size += 1, // type code
154                Some(value) => items_size += value.size(),
155            }
156        }
157        items_size + 1 + 4 + 4 // items, type code, typeId, len
158    }
159}
160
161impl<T: WritableType + ReadableType> ReadableType for Vec<Option<T>> {
162    fn read_unwrapped(type_code: TypeCode, reader: &mut impl Read) -> IgniteResult<Option<Self>> {
163        match type_code {
164            TypeCode::Null => Ok(None),
165            TypeCode::ArrObj => {
166                read_i32(reader)?; // ignore type id
167                let len = read_i32(reader)?;
168                let mut data: Vec<Option<T>> = Vec::with_capacity(len as usize);
169                for _ in 0..len {
170                    let item = T::read(reader)?;
171                    data.push(item);
172                }
173                Ok(Some(data))
174            }
175            TypeCode::Collection => {
176                let len = read_i32(reader)?;
177                read_i8(reader)?; // ignore collection type
178                let mut data: Vec<Option<T>> = Vec::with_capacity(len as usize);
179                for _ in 0..len {
180                    let item = T::read(reader)?;
181                    data.push(item);
182                }
183                Ok(Some(data))
184            }
185            _ => Err(IgniteError::from("Expected Array or Collection!")),
186        }
187    }
188}
189
190impl<T: WritableType> WritableType for Option<T> {
191    fn write(&self, writer: &mut dyn Write) -> io::Result<()> {
192        match self {
193            None => write_u8(writer, TypeCode::Null as u8),
194            Some(inner) => inner.write(writer),
195        }
196    }
197
198    fn size(&self) -> usize {
199        match self {
200            None => 1, // type code
201            Some(inner) => inner.size(),
202        }
203    }
204}
205
206impl<T: ReadableType> ReadableType for Option<T> {
207    fn read_unwrapped(type_code: TypeCode, reader: &mut impl Read) -> IgniteResult<Option<Self>> {
208        let inner_op = T::read_unwrapped(type_code, reader)?;
209        match inner_op {
210            None => Ok(None),
211            Some(inner) => Ok(Some(Some(inner))),
212        }
213    }
214}