1use std::collections::hash_map::DefaultHasher;
5use std::hash::{Hash, Hasher};
6use std::io::{Cursor, Read, Result as IoResult, Write};
7use std::str;
8
9use crate::errors::{Result, ValidationError, ValidationResult};
10use crate::models;
11
12use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
13use once_cell::sync::Lazy;
14use uuid::v1::{Context, Timestamp};
15use uuid::Uuid;
16
17const NODE_ID: [u8; 6] = [0, 0, 0, 0, 0, 0];
18
19static CONTEXT: Lazy<Context> = Lazy::new(|| Context::new(0));
20
21pub enum Component<'a> {
24 Uuid(Uuid),
26 FixedLengthString(&'a str),
28 Identifier(models::Identifier),
30 Json(&'a models::Json),
32}
33
34impl Component<'_> {
35 pub fn byte_len(&self) -> usize {
38 match *self {
39 Component::Uuid(_) => 16,
40 Component::FixedLengthString(s) => s.len(),
41 Component::Identifier(t) => t.0.len() + 1,
42 Component::Json(_) => 8,
43 }
44 }
45
46 pub fn write(&self, cursor: &mut Cursor<Vec<u8>>) -> IoResult<()> {
48 match *self {
49 Component::Uuid(uuid) => cursor.write_all(uuid.as_bytes()),
50 Component::FixedLengthString(s) => cursor.write_all(s.as_bytes()),
51 Component::Identifier(i) => {
52 cursor.write_all(&[i.0.len() as u8])?;
53 cursor.write_all(i.0.as_bytes())
54 }
55 Component::Json(json) => {
56 let mut hasher = DefaultHasher::new();
57 json.hash(&mut hasher);
58 let hash = hasher.finish();
59 cursor.write_u64::<BigEndian>(hash)
60 }
61 }
62 }
63}
64
65pub fn build(components: &[Component]) -> Vec<u8> {
70 let len = components.iter().fold(0, |len, component| len + component.byte_len());
71 let mut cursor: Cursor<Vec<u8>> = Cursor::new(Vec::with_capacity(len));
72 for component in components {
73 component
74 .write(&mut cursor)
75 .expect("failed to write bytes to in-memory buffer");
76 }
77
78 cursor.into_inner()
79}
80
81pub fn read_uuid<T: AsRef<[u8]>>(cursor: &mut Cursor<T>) -> Result<Uuid> {
86 let mut buf: [u8; 16] = [0; 16];
87 cursor.read_exact(&mut buf)?;
88 let uuid = Uuid::from_slice(&buf).unwrap();
89 Ok(uuid)
90}
91
92pub unsafe fn read_identifier<T: AsRef<[u8]>>(cursor: &mut Cursor<T>) -> Result<models::Identifier> {
102 let t_len = {
103 let mut buf: [u8; 1] = [0; 1];
104 cursor.read_exact(&mut buf)?;
105 buf[0] as usize
106 };
107
108 let mut buf = vec![0u8; t_len];
109 cursor.read_exact(&mut buf)?;
110 let s = str::from_utf8_unchecked(&buf).to_string();
111 Ok(models::Identifier::new_unchecked(s))
112}
113
114pub fn read_fixed_length_string<T: AsRef<[u8]>>(cursor: &mut Cursor<T>) -> Result<String> {
119 let mut buf = String::new();
120 cursor.read_to_string(&mut buf)?;
121 Ok(buf)
122}
123
124pub fn read_u64<T: AsRef<[u8]>>(cursor: &mut Cursor<T>) -> Result<u64> {
129 let i = cursor.read_u64::<BigEndian>()?;
130 Ok(i)
131}
132
133pub fn generate_uuid_v1() -> Uuid {
136 Uuid::new_v1(Timestamp::now(&*CONTEXT), &NODE_ID)
137}
138
139pub fn next_uuid(uuid: Uuid) -> ValidationResult<Uuid> {
148 let mut bytes = *uuid.as_bytes();
149
150 for i in (0..16).rev() {
151 if bytes[i] < 255 {
152 bytes[i] += 1;
153 return Ok(Uuid::from_slice(&bytes[..]).unwrap());
154 } else {
155 bytes[i] = 0;
156 }
157 }
158
159 Err(ValidationError::CannotIncrementUuid)
160}
161
162pub fn extract_vertices(mut output: Vec<models::QueryOutputValue>) -> Option<Vec<models::Vertex>> {
167 if let Some(models::QueryOutputValue::Vertices(vertices)) = output.pop() {
168 Some(vertices)
169 } else {
170 None
171 }
172}
173
174pub fn extract_edges(mut output: Vec<models::QueryOutputValue>) -> Option<Vec<models::Edge>> {
179 if let Some(models::QueryOutputValue::Edges(edges)) = output.pop() {
180 Some(edges)
181 } else {
182 None
183 }
184}
185
186pub fn extract_count(mut output: Vec<models::QueryOutputValue>) -> Option<u64> {
191 if let Some(models::QueryOutputValue::Count(count)) = output.pop() {
192 Some(count)
193 } else {
194 None
195 }
196}
197
198pub fn extract_vertex_properties(mut output: Vec<models::QueryOutputValue>) -> Option<Vec<models::VertexProperties>> {
203 if let Some(models::QueryOutputValue::VertexProperties(props)) = output.pop() {
204 Some(props)
205 } else {
206 None
207 }
208}
209
210pub fn extract_edge_properties(mut output: Vec<models::QueryOutputValue>) -> Option<Vec<models::EdgeProperties>> {
215 if let Some(models::QueryOutputValue::EdgeProperties(props)) = output.pop() {
216 Some(props)
217 } else {
218 None
219 }
220}
221
222#[cfg(test)]
223mod tests {
224 use super::{
225 extract_count, extract_edge_properties, extract_edges, extract_vertex_properties, extract_vertices,
226 generate_uuid_v1, next_uuid,
227 };
228 use core::str::FromStr;
229 use uuid::Uuid;
230
231 #[test]
232 fn should_generate_new_uuid_v1() {
233 let first = generate_uuid_v1();
234 let second = generate_uuid_v1();
235 assert_ne!(first, second);
236 }
237
238 #[test]
239 fn should_generate_next_uuid() {
240 let result = next_uuid(Uuid::from_str("16151dea-a538-4bf1-9559-851e256cf139").unwrap());
241 assert!(result.is_ok());
242 assert_eq!(
243 result.unwrap(),
244 Uuid::from_str("16151dea-a538-4bf1-9559-851e256cf13a").unwrap()
245 );
246
247 let from_uuid = Uuid::from_str("ffffffff-ffff-ffff-ffff-ffffffffffff").unwrap();
248 assert!(next_uuid(from_uuid).is_err());
249 }
250
251 #[test]
252 fn should_not_extract_vertices_on_empty() {
253 assert_eq!(extract_vertices(vec![]), None);
254 }
255
256 #[test]
257 fn should_not_extract_edges_on_empty() {
258 assert_eq!(extract_edges(vec![]), None);
259 }
260
261 #[test]
262 fn should_not_extract_count_on_empty() {
263 assert_eq!(extract_count(vec![]), None);
264 }
265
266 #[test]
267 fn should_not_extract_vertex_properties_on_empty() {
268 assert_eq!(extract_vertex_properties(vec![]), None);
269 }
270
271 #[test]
272 fn should_not_extract_edge_properties_on_empty() {
273 assert_eq!(extract_edge_properties(vec![]), None);
274 }
275}