amq_proto/
table.rs

1use std::collections::HashMap;
2use error::*;
3use std::io::{Read, Write};
4use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
5
6#[derive(Debug, Clone, PartialEq)]
7pub enum TableEntry {
8    Bool(bool),
9    ShortShortInt(i8),
10    ShortShortUint(u8),
11    ShortInt(i16),
12    ShortUint(u16),
13    LongInt(i32),
14    LongUint(u32),
15    LongLongInt(i64),
16    LongLongUint(u64),
17    Float(f32),
18    Double(f64),
19    DecimalValue(u8, u32),
20    // ShortString(String),
21    LongString(String),
22    FieldArray(Vec<TableEntry>),
23    Timestamp(u64),
24    FieldTable(Table),
25    Void,
26}
27
28pub type Table = HashMap<String, TableEntry>;
29
30pub trait Init {
31    fn new() -> Self;
32}
33
34impl Init for Table {
35    fn new() -> Self {
36        HashMap::new()
37    }
38}
39
40fn read_table_entry<T>(reader: &mut T) -> Result<(TableEntry, usize)> where T: Read {
41    let (entry, entry_size) = match try!(reader.read_u8()) {
42        b't' => (TableEntry::Bool(!try!(reader.read_u8()) != 0), 1),
43        b'b' => (TableEntry::ShortShortInt(try!(reader.read_i8())), 1),
44        b'B' => (TableEntry::ShortShortUint(try!(reader.read_u8())), 1),
45        b'U' => (TableEntry::ShortInt(try!(reader.read_i16::<BigEndian>())), 2),
46        b'u' => (TableEntry::ShortUint(try!(reader.read_u16::<BigEndian>())), 2),
47        b'I' => (TableEntry::LongInt(try!(reader.read_i32::<BigEndian>())), 4),
48        b'i' => (TableEntry::LongUint(try!(reader.read_u32::<BigEndian>())), 4),
49        b'L' => (TableEntry::LongLongInt(try!(reader.read_i64::<BigEndian>())), 8),
50        b'l' => (TableEntry::LongLongUint(try!(reader.read_u64::<BigEndian>())), 8),
51        b'f' => (TableEntry::Float(try!(reader.read_f32::<BigEndian>())), 4),
52        b'd' => (TableEntry::Double(try!(reader.read_f64::<BigEndian>())), 8),
53        b'D' => ({
54            TableEntry::DecimalValue(try!(reader.read_u8()), try!(reader.read_u32::<BigEndian>()))
55        }, 5),
56        // b's' => {
57        //  let size = try!(reader.read_u8()) as usize;
58        // let str =
59        // String::from_utf8_lossy(try!(reader.read_exact(size)).as_slice()).to_string();
60        //  ShortString(str)
61        // },
62        b'S' => {
63            let size = try!(reader.read_u32::<BigEndian>()) as usize;
64            let mut buffer: Vec<u8> = vec![0u8; size];
65            try!(reader.read(&mut buffer[..]));
66            let string = String::from_utf8_lossy(&buffer).to_string();
67            let entry = TableEntry::LongString(string);
68            (entry, 4 + size)
69        },
70        b'A' => {
71            let array_len = try!(reader.read_u32::<BigEndian>()) as usize;
72            let mut read_len = 0;
73            let mut arr = Vec::new();
74            while read_len < array_len {
75                let (entry, entry_len) = try!(read_table_entry(reader));
76                read_len += entry_len;
77                arr.push(entry)
78            }
79            let entry = TableEntry::FieldArray(arr);
80            (entry, 4 + array_len)
81        },
82        b'T' => (TableEntry::Timestamp(try!(reader.read_u64::<BigEndian>())), 8),
83        b'F' => {
84            let (table, table_size) = try!(decode_table(reader));
85            let entry = TableEntry::FieldTable(table);
86            (entry, table_size)
87        },
88        b'V' => (TableEntry::Void, 0),
89        x => {
90            debug!("Unknown type: {}", x);
91            return Err(ErrorKind::Protocol("Unknown type".to_string()).into());
92        }
93    };
94    Ok((entry, entry_size + 1)) // including entry_type
95}
96
97fn write_table_entry(writer: &mut Vec<u8>, table_entry: &TableEntry) -> Result<()> {
98    match *table_entry {
99        TableEntry::Bool(val) => {
100            try!(writer.write_u8(b't'));
101            try!(writer.write_u8(val as u8));
102        }
103        TableEntry::ShortShortInt(val) => {
104            try!(writer.write_u8(b'b'));
105            try!(writer.write_i8(val));
106        }
107        TableEntry::ShortShortUint(val) => {
108            try!(writer.write_u8(b'B'));
109            try!(writer.write_u8(val));
110        }
111        TableEntry::ShortInt(val) => {
112            try!(writer.write_u8(b'U'));
113            try!(writer.write_i16::<BigEndian>(val));
114        }
115        TableEntry::ShortUint(val) => {
116            try!(writer.write_u8(b'u'));
117            try!(writer.write_u16::<BigEndian>(val));
118        }
119        TableEntry::LongInt(val) => {
120            try!(writer.write_u8(b'I'));
121            try!(writer.write_i32::<BigEndian>(val));
122        }
123        TableEntry::LongUint(val) => {
124            try!(writer.write_u8(b'i'));
125            try!(writer.write_u32::<BigEndian>(val));
126        }
127        TableEntry::LongLongInt(val) => {
128            try!(writer.write_u8(b'L'));
129            try!(writer.write_i64::<BigEndian>(val));
130        }
131        TableEntry::LongLongUint(val) => {
132            try!(writer.write_u8(b'l'));
133            try!(writer.write_u64::<BigEndian>(val));
134        }
135        TableEntry::Float(val) => {
136            try!(writer.write_u8(b'f'));
137            try!(writer.write_f32::<BigEndian>(val));
138        }
139        TableEntry::Double(val) => {
140            try!(writer.write_u8(b'd'));
141            try!(writer.write_f64::<BigEndian>(val));
142        }
143        TableEntry::DecimalValue(scale, value) => {
144            try!(writer.write_u8(b'D'));
145            try!(writer.write_u8(scale));
146            try!(writer.write_u32::<BigEndian>(value));
147        }
148        // ShortString(str) => {
149        //  try!(writer.write_u8(b's'));
150        //  try!(writer.write_u8(str.len() as u8));
151        //  try!(writer.write_all(str.as_bytes()));
152        // },
153        TableEntry::LongString(ref str) => {
154            try!(writer.write_u8(b'S'));
155            try!(writer.write_u32::<BigEndian>(str.len() as u32));
156            try!(writer.write_all(str.as_bytes()));
157        }
158        TableEntry::FieldArray(ref arr) => {
159            try!(writer.write_u8(b'A'));
160            let mut tmp_buffer = vec![];
161            for item in arr.iter() {
162                try!(write_table_entry(&mut tmp_buffer, item));
163            }
164            try!(writer.write_u32::<BigEndian>(tmp_buffer.len() as u32));
165            try!(writer.write(&tmp_buffer));
166        }
167        TableEntry::Timestamp(val) => {
168            try!(writer.write_u8(b'T'));
169            try!(writer.write_u64::<BigEndian>(val))
170        }
171        TableEntry::FieldTable(ref table) => {
172            try!(writer.write_u8(b'F'));
173            try!(encode_table(writer, table));
174        }
175        TableEntry::Void => try!(writer.write_u8(b'V')),
176    }
177    Ok(())
178}
179
180pub fn decode_table<T>(reader: &mut T) -> Result<(Table, usize)> where T: Read {
181    let mut table = Table::new();
182    let table_len = try!(reader.read_u32::<BigEndian>()) as usize;
183    debug!("decoding table, len: {}", table_len);
184    let mut bytes_read = 0;
185
186    while bytes_read < table_len {
187        let field_name_len = try!(reader.read_u8()) as usize;
188        let mut field_name: Vec<u8> = vec![0u8; field_name_len];
189        try!(reader.read(&mut field_name[..]));
190        let (table_entry, table_entry_size) = try!(read_table_entry(reader));
191        let stringified_field_name = String::from_utf8_lossy(&field_name).to_string();
192        debug!("Read table entry: {:?}:{} = {:?}", stringified_field_name, table_entry_size, table_entry);
193        table.insert(stringified_field_name, table_entry);
194        bytes_read += 1 + field_name_len + table_entry_size; // a byte for length of the field_name
195        debug!("bytes_read: {} of {}", bytes_read, table_len);
196    }
197    debug!("table decoded, table len: {}, bytes_read: {}", table_len, bytes_read);
198    Ok((table, bytes_read + 4)) // 4 bytes for the table_len
199}
200
201pub fn encode_table<T: Write>(writer: &mut T, table: &Table) -> Result<()> {
202    let mut tmp_buffer = vec![];
203    for (field_name, table_entry) in table.iter() {
204        try!(tmp_buffer.write_u8(field_name.len() as u8));
205        try!(tmp_buffer.write_all(field_name.as_bytes()));
206        try!(write_table_entry(&mut tmp_buffer, table_entry));
207    }
208    try!(writer.write_u32::<BigEndian>(tmp_buffer.len() as u32));
209    try!(writer.write_all(&tmp_buffer));
210    Ok(())
211}