Skip to main content

reddb_server/storage/query/
binary.rs

1//! GraphBinary Serialization
2//!
3//! Binary serialization format for graph traversal components.
4//!
5//! # Format
6//!
7//! Each value is serialized as:
8//! ```text
9//! ┌──────────┬───────────┬────────────┬─────────┐
10//! │ type_code│ type_info │ value_flag │  value  │
11//! │  (1 byte)│ (optional)│  (1 byte)  │(variable│
12//! └──────────┴───────────┴────────────┴─────────┘
13//! ```
14//!
15//! # Type Codes
16//!
17//! - 0x00: Custom
18//! - 0x01: Int32
19//! - 0x02: Int64
20//! - 0x03: Float
21//! - 0x04: Double
22//! - 0x05: String
23//! - 0x06: List
24//! - 0x07: Map
25//! - 0x08: Set
26//! - 0x09: UUID
27//! - 0x0A: Edge
28//! - 0x0B: Vertex
29//! - 0x0C: Path
30//! - 0x0D: Property
31//! - 0x0E: Traverser
32//! - 0x0F: Bytecode (traversal plan)
33//! - 0x10: Binding
34//! - 0x11: Step (custom step type)
35//!
36//! # Value Flags
37//!
38//! - 0x00: Value present
39//! - 0x01: Null value
40//! - 0x02: Bulk value (for Traverser)
41//!
42//! # References
43//!
44//! - TinkerPop GraphBinary specification
45//! - Gremlin bytecode format
46
47/// Type codes for GraphBinary serialization
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49#[repr(u8)]
50pub enum TypeCode {
51    /// Custom type with type-info
52    Custom = 0x00,
53    /// 32-bit signed integer
54    Int32 = 0x01,
55    /// 64-bit signed integer
56    Int64 = 0x02,
57    /// 32-bit float
58    Float = 0x03,
59    /// 64-bit double
60    Double = 0x04,
61    /// UTF-8 string
62    String = 0x05,
63    /// List of values
64    List = 0x06,
65    /// Key-value map
66    Map = 0x07,
67    /// Set of unique values
68    Set = 0x08,
69    /// UUID (16 bytes)
70    Uuid = 0x09,
71    /// Graph edge
72    Edge = 0x0A,
73    /// Graph vertex
74    Vertex = 0x0B,
75    /// Traversal path
76    Path = 0x0C,
77    /// Property (key-value)
78    Property = 0x0D,
79    /// Traverser (value + bulk + path)
80    Traverser = 0x0E,
81    /// Bytecode (traversal plan)
82    Bytecode = 0x0F,
83    /// Binding (variable -> value)
84    Binding = 0x10,
85    /// Step type
86    Step = 0x11,
87    /// Boolean
88    Boolean = 0x12,
89    /// Null type
90    Null = 0x13,
91    /// Bytes
92    Bytes = 0x14,
93}
94
95impl TypeCode {
96    /// Convert from byte
97    pub fn from_byte(b: u8) -> Option<Self> {
98        match b {
99            0x00 => Some(TypeCode::Custom),
100            0x01 => Some(TypeCode::Int32),
101            0x02 => Some(TypeCode::Int64),
102            0x03 => Some(TypeCode::Float),
103            0x04 => Some(TypeCode::Double),
104            0x05 => Some(TypeCode::String),
105            0x06 => Some(TypeCode::List),
106            0x07 => Some(TypeCode::Map),
107            0x08 => Some(TypeCode::Set),
108            0x09 => Some(TypeCode::Uuid),
109            0x0A => Some(TypeCode::Edge),
110            0x0B => Some(TypeCode::Vertex),
111            0x0C => Some(TypeCode::Path),
112            0x0D => Some(TypeCode::Property),
113            0x0E => Some(TypeCode::Traverser),
114            0x0F => Some(TypeCode::Bytecode),
115            0x10 => Some(TypeCode::Binding),
116            0x11 => Some(TypeCode::Step),
117            0x12 => Some(TypeCode::Boolean),
118            0x13 => Some(TypeCode::Null),
119            0x14 => Some(TypeCode::Bytes),
120            _ => None,
121        }
122    }
123
124    /// Get type name
125    pub fn name(&self) -> &'static str {
126        match self {
127            TypeCode::Custom => "Custom",
128            TypeCode::Int32 => "Int32",
129            TypeCode::Int64 => "Int64",
130            TypeCode::Float => "Float",
131            TypeCode::Double => "Double",
132            TypeCode::String => "String",
133            TypeCode::List => "List",
134            TypeCode::Map => "Map",
135            TypeCode::Set => "Set",
136            TypeCode::Uuid => "UUID",
137            TypeCode::Edge => "Edge",
138            TypeCode::Vertex => "Vertex",
139            TypeCode::Path => "Path",
140            TypeCode::Property => "Property",
141            TypeCode::Traverser => "Traverser",
142            TypeCode::Bytecode => "Bytecode",
143            TypeCode::Binding => "Binding",
144            TypeCode::Step => "Step",
145            TypeCode::Boolean => "Boolean",
146            TypeCode::Null => "Null",
147            TypeCode::Bytes => "Bytes",
148        }
149    }
150}
151
152/// Value flags for null/bulk handling
153#[derive(Debug, Clone, Copy, PartialEq, Eq)]
154#[repr(u8)]
155pub enum ValueFlag {
156    /// Value is present
157    Present = 0x00,
158    /// Value is null
159    Null = 0x01,
160    /// Value has bulk count (for Traverser)
161    Bulk = 0x02,
162}
163
164impl ValueFlag {
165    /// Convert from byte
166    pub fn from_byte(b: u8) -> Self {
167        match b {
168            0x01 => ValueFlag::Null,
169            0x02 => ValueFlag::Bulk,
170            _ => ValueFlag::Present,
171        }
172    }
173}
174
175/// Type information for custom types
176#[derive(Debug, Clone)]
177pub struct TypeInfo {
178    /// Custom type name
179    pub name: String,
180    /// Schema version
181    pub version: u16,
182}
183
184impl TypeInfo {
185    /// Create type info
186    pub fn new(name: impl Into<String>, version: u16) -> Self {
187        Self {
188            name: name.into(),
189            version,
190        }
191    }
192
193    /// Serialize type info
194    pub fn to_bytes(&self) -> Vec<u8> {
195        let mut buf = Vec::new();
196        // Length-prefixed name
197        let name_bytes = self.name.as_bytes();
198        buf.extend(&(name_bytes.len() as u16).to_le_bytes());
199        buf.extend(name_bytes);
200        // Version
201        buf.extend(&self.version.to_le_bytes());
202        buf
203    }
204
205    /// Deserialize type info
206    pub fn from_bytes(data: &[u8]) -> Option<(Self, usize)> {
207        if data.len() < 4 {
208            return None;
209        }
210
211        let name_len = u16::from_le_bytes([data[0], data[1]]) as usize;
212        if data.len() < 4 + name_len {
213            return None;
214        }
215
216        let name = String::from_utf8(data[2..2 + name_len].to_vec()).ok()?;
217        let version = u16::from_le_bytes([data[2 + name_len], data[3 + name_len]]);
218
219        Some((Self { name, version }, 4 + name_len))
220    }
221}
222
223/// Binary value representation
224#[derive(Debug, Clone)]
225pub enum BinaryValue {
226    /// Null value
227    Null,
228    /// Boolean
229    Boolean(bool),
230    /// 32-bit integer
231    Int32(i32),
232    /// 64-bit integer
233    Int64(i64),
234    /// Float
235    Float(f32),
236    /// Double
237    Double(f64),
238    /// String
239    String(String),
240    /// Bytes
241    Bytes(Vec<u8>),
242    /// List of values
243    List(Vec<BinaryValue>),
244    /// Map of key-value pairs
245    Map(Vec<(BinaryValue, BinaryValue)>),
246    /// UUID (16 bytes)
247    Uuid([u8; 16]),
248    /// Vertex with ID and label
249    Vertex { id: Box<BinaryValue>, label: String },
250    /// Edge with ID, label, in/out vertices
251    Edge {
252        id: Box<BinaryValue>,
253        label: String,
254        in_v: Box<BinaryValue>,
255        out_v: Box<BinaryValue>,
256    },
257    /// Property (key, value)
258    Property {
259        key: String,
260        value: Box<BinaryValue>,
261    },
262    /// Traverser (value, bulk, path)
263    Traverser { value: Box<BinaryValue>, bulk: u64 },
264    /// Bytecode instruction
265    Bytecode(Bytecode),
266    /// Binding (name -> value)
267    Binding {
268        name: String,
269        value: Box<BinaryValue>,
270    },
271    /// Custom type
272    Custom { type_info: TypeInfo, data: Vec<u8> },
273}
274
275impl BinaryValue {
276    /// Get type code for this value
277    pub fn type_code(&self) -> TypeCode {
278        match self {
279            BinaryValue::Null => TypeCode::Null,
280            BinaryValue::Boolean(_) => TypeCode::Boolean,
281            BinaryValue::Int32(_) => TypeCode::Int32,
282            BinaryValue::Int64(_) => TypeCode::Int64,
283            BinaryValue::Float(_) => TypeCode::Float,
284            BinaryValue::Double(_) => TypeCode::Double,
285            BinaryValue::String(_) => TypeCode::String,
286            BinaryValue::Bytes(_) => TypeCode::Bytes,
287            BinaryValue::List(_) => TypeCode::List,
288            BinaryValue::Map(_) => TypeCode::Map,
289            BinaryValue::Uuid(_) => TypeCode::Uuid,
290            BinaryValue::Vertex { .. } => TypeCode::Vertex,
291            BinaryValue::Edge { .. } => TypeCode::Edge,
292            BinaryValue::Property { .. } => TypeCode::Property,
293            BinaryValue::Traverser { .. } => TypeCode::Traverser,
294            BinaryValue::Bytecode(_) => TypeCode::Bytecode,
295            BinaryValue::Binding { .. } => TypeCode::Binding,
296            BinaryValue::Custom { .. } => TypeCode::Custom,
297        }
298    }
299
300    /// Check if value is null
301    pub fn is_null(&self) -> bool {
302        matches!(self, BinaryValue::Null)
303    }
304}
305
306/// Bytecode representation for traversal plans
307#[derive(Debug, Clone)]
308pub struct Bytecode {
309    /// Source instructions (start of traversal)
310    pub sources: Vec<Instruction>,
311    /// Step instructions
312    pub steps: Vec<Instruction>,
313}
314
315impl Bytecode {
316    /// Create empty bytecode
317    pub fn new() -> Self {
318        Self {
319            sources: Vec::new(),
320            steps: Vec::new(),
321        }
322    }
323
324    /// Add source instruction (e.g., V(), E())
325    pub fn add_source(&mut self, name: &str, args: Vec<BinaryValue>) {
326        self.sources.push(Instruction::new(name, args));
327    }
328
329    /// Add step instruction
330    pub fn add_step(&mut self, name: &str, args: Vec<BinaryValue>) {
331        self.steps.push(Instruction::new(name, args));
332    }
333}
334
335impl Default for Bytecode {
336    fn default() -> Self {
337        Self::new()
338    }
339}
340
341/// Single bytecode instruction
342#[derive(Debug, Clone)]
343pub struct Instruction {
344    /// Step name (e.g., "V", "out", "has", "select")
345    pub name: String,
346    /// Arguments
347    pub args: Vec<BinaryValue>,
348}
349
350impl Instruction {
351    /// Create new instruction
352    pub fn new(name: impl Into<String>, args: Vec<BinaryValue>) -> Self {
353        Self {
354            name: name.into(),
355            args,
356        }
357    }
358}
359
360/// Binary serializer
361pub struct BinarySerializer;
362
363impl BinarySerializer {
364    /// Serialize value to bytes
365    pub fn serialize(value: &BinaryValue) -> Vec<u8> {
366        let mut buf = Vec::new();
367        Self::write_value(&mut buf, value);
368        buf
369    }
370
371    /// Write value to buffer
372    fn write_value(buf: &mut Vec<u8>, value: &BinaryValue) {
373        // Write type code
374        buf.push(value.type_code() as u8);
375
376        match value {
377            BinaryValue::Null => {
378                buf.push(ValueFlag::Null as u8);
379            }
380            BinaryValue::Boolean(b) => {
381                buf.push(ValueFlag::Present as u8);
382                buf.push(if *b { 1 } else { 0 });
383            }
384            BinaryValue::Int32(i) => {
385                buf.push(ValueFlag::Present as u8);
386                buf.extend(&i.to_le_bytes());
387            }
388            BinaryValue::Int64(i) => {
389                buf.push(ValueFlag::Present as u8);
390                buf.extend(&i.to_le_bytes());
391            }
392            BinaryValue::Float(f) => {
393                buf.push(ValueFlag::Present as u8);
394                buf.extend(&f.to_le_bytes());
395            }
396            BinaryValue::Double(d) => {
397                buf.push(ValueFlag::Present as u8);
398                buf.extend(&d.to_le_bytes());
399            }
400            BinaryValue::String(s) => {
401                buf.push(ValueFlag::Present as u8);
402                Self::write_string(buf, s);
403            }
404            BinaryValue::Bytes(b) => {
405                buf.push(ValueFlag::Present as u8);
406                buf.extend(&(b.len() as u32).to_le_bytes());
407                buf.extend(b);
408            }
409            BinaryValue::List(items) => {
410                buf.push(ValueFlag::Present as u8);
411                buf.extend(&(items.len() as u32).to_le_bytes());
412                for item in items {
413                    Self::write_value(buf, item);
414                }
415            }
416            BinaryValue::Map(pairs) => {
417                buf.push(ValueFlag::Present as u8);
418                buf.extend(&(pairs.len() as u32).to_le_bytes());
419                for (k, v) in pairs {
420                    Self::write_value(buf, k);
421                    Self::write_value(buf, v);
422                }
423            }
424            BinaryValue::Uuid(bytes) => {
425                buf.push(ValueFlag::Present as u8);
426                buf.extend(bytes);
427            }
428            BinaryValue::Vertex { id, label } => {
429                buf.push(ValueFlag::Present as u8);
430                Self::write_value(buf, id);
431                Self::write_string(buf, label);
432            }
433            BinaryValue::Edge {
434                id,
435                label,
436                in_v,
437                out_v,
438            } => {
439                buf.push(ValueFlag::Present as u8);
440                Self::write_value(buf, id);
441                Self::write_string(buf, label);
442                Self::write_value(buf, in_v);
443                Self::write_value(buf, out_v);
444            }
445            BinaryValue::Property { key, value } => {
446                buf.push(ValueFlag::Present as u8);
447                Self::write_string(buf, key);
448                Self::write_value(buf, value);
449            }
450            BinaryValue::Traverser { value, bulk } => {
451                buf.push(ValueFlag::Bulk as u8);
452                buf.extend(&bulk.to_le_bytes());
453                Self::write_value(buf, value);
454            }
455            BinaryValue::Bytecode(bc) => {
456                buf.push(ValueFlag::Present as u8);
457                Self::write_bytecode(buf, bc);
458            }
459            BinaryValue::Binding { name, value } => {
460                buf.push(ValueFlag::Present as u8);
461                Self::write_string(buf, name);
462                Self::write_value(buf, value);
463            }
464            BinaryValue::Custom { type_info, data } => {
465                buf.push(ValueFlag::Present as u8);
466                buf.extend(type_info.to_bytes());
467                buf.extend(&(data.len() as u32).to_le_bytes());
468                buf.extend(data);
469            }
470        }
471    }
472
473    /// Write length-prefixed string
474    fn write_string(buf: &mut Vec<u8>, s: &str) {
475        let bytes = s.as_bytes();
476        buf.extend(&(bytes.len() as u32).to_le_bytes());
477        buf.extend(bytes);
478    }
479
480    /// Write bytecode
481    fn write_bytecode(buf: &mut Vec<u8>, bc: &Bytecode) {
482        // Sources count
483        buf.extend(&(bc.sources.len() as u32).to_le_bytes());
484        for inst in &bc.sources {
485            Self::write_instruction(buf, inst);
486        }
487
488        // Steps count
489        buf.extend(&(bc.steps.len() as u32).to_le_bytes());
490        for inst in &bc.steps {
491            Self::write_instruction(buf, inst);
492        }
493    }
494
495    /// Write single instruction
496    fn write_instruction(buf: &mut Vec<u8>, inst: &Instruction) {
497        Self::write_string(buf, &inst.name);
498        buf.extend(&(inst.args.len() as u32).to_le_bytes());
499        for arg in &inst.args {
500            Self::write_value(buf, arg);
501        }
502    }
503}
504
505/// Binary deserializer
506pub struct BinaryDeserializer;
507
508impl BinaryDeserializer {
509    /// Deserialize value from bytes
510    pub fn deserialize(data: &[u8]) -> Option<(BinaryValue, usize)> {
511        Self::read_value(data)
512    }
513
514    /// Read value from buffer
515    fn read_value(data: &[u8]) -> Option<(BinaryValue, usize)> {
516        if data.len() < 2 {
517            return None;
518        }
519
520        let type_code = TypeCode::from_byte(data[0])?;
521        let flag = ValueFlag::from_byte(data[1]);
522
523        // Handle null
524        if flag == ValueFlag::Null {
525            return Some((BinaryValue::Null, 2));
526        }
527
528        let mut offset = 2;
529
530        let value = match type_code {
531            TypeCode::Null => BinaryValue::Null,
532            TypeCode::Boolean => {
533                if data.len() < offset + 1 {
534                    return None;
535                }
536                let b = data[offset] != 0;
537                offset += 1;
538                BinaryValue::Boolean(b)
539            }
540            TypeCode::Int32 => {
541                if data.len() < offset + 4 {
542                    return None;
543                }
544                let i = i32::from_le_bytes(data[offset..offset + 4].try_into().ok()?);
545                offset += 4;
546                BinaryValue::Int32(i)
547            }
548            TypeCode::Int64 => {
549                if data.len() < offset + 8 {
550                    return None;
551                }
552                let i = i64::from_le_bytes(data[offset..offset + 8].try_into().ok()?);
553                offset += 8;
554                BinaryValue::Int64(i)
555            }
556            TypeCode::Float => {
557                if data.len() < offset + 4 {
558                    return None;
559                }
560                let f = f32::from_le_bytes(data[offset..offset + 4].try_into().ok()?);
561                offset += 4;
562                BinaryValue::Float(f)
563            }
564            TypeCode::Double => {
565                if data.len() < offset + 8 {
566                    return None;
567                }
568                let d = f64::from_le_bytes(data[offset..offset + 8].try_into().ok()?);
569                offset += 8;
570                BinaryValue::Double(d)
571            }
572            TypeCode::String => {
573                let (s, len) = Self::read_string(&data[offset..])?;
574                offset += len;
575                BinaryValue::String(s)
576            }
577            TypeCode::Bytes => {
578                if data.len() < offset + 4 {
579                    return None;
580                }
581                let len = u32::from_le_bytes(data[offset..offset + 4].try_into().ok()?) as usize;
582                offset += 4;
583                if data.len() < offset + len {
584                    return None;
585                }
586                let bytes = data[offset..offset + len].to_vec();
587                offset += len;
588                BinaryValue::Bytes(bytes)
589            }
590            TypeCode::List => {
591                if data.len() < offset + 4 {
592                    return None;
593                }
594                let count = u32::from_le_bytes(data[offset..offset + 4].try_into().ok()?) as usize;
595                offset += 4;
596
597                let mut items = Vec::with_capacity(count);
598                for _ in 0..count {
599                    let (item, len) = Self::read_value(&data[offset..])?;
600                    offset += len;
601                    items.push(item);
602                }
603                BinaryValue::List(items)
604            }
605            TypeCode::Map => {
606                if data.len() < offset + 4 {
607                    return None;
608                }
609                let count = u32::from_le_bytes(data[offset..offset + 4].try_into().ok()?) as usize;
610                offset += 4;
611
612                let mut pairs = Vec::with_capacity(count);
613                for _ in 0..count {
614                    let (key, len1) = Self::read_value(&data[offset..])?;
615                    offset += len1;
616                    let (val, len2) = Self::read_value(&data[offset..])?;
617                    offset += len2;
618                    pairs.push((key, val));
619                }
620                BinaryValue::Map(pairs)
621            }
622            TypeCode::Uuid => {
623                if data.len() < offset + 16 {
624                    return None;
625                }
626                let mut bytes = [0u8; 16];
627                bytes.copy_from_slice(&data[offset..offset + 16]);
628                offset += 16;
629                BinaryValue::Uuid(bytes)
630            }
631            TypeCode::Traverser => {
632                // Bulk count
633                if data.len() < offset + 8 {
634                    return None;
635                }
636                let bulk = u64::from_le_bytes(data[offset..offset + 8].try_into().ok()?);
637                offset += 8;
638                // Value
639                let (value, len) = Self::read_value(&data[offset..])?;
640                offset += len;
641                BinaryValue::Traverser {
642                    value: Box::new(value),
643                    bulk,
644                }
645            }
646            TypeCode::Bytecode => {
647                let (bc, len) = Self::read_bytecode(&data[offset..])?;
648                offset += len;
649                BinaryValue::Bytecode(bc)
650            }
651            _ => return None, // Other types not fully implemented
652        };
653
654        Some((value, offset))
655    }
656
657    /// Read length-prefixed string
658    fn read_string(data: &[u8]) -> Option<(String, usize)> {
659        if data.len() < 4 {
660            return None;
661        }
662        let len = u32::from_le_bytes(data[0..4].try_into().ok()?) as usize;
663        if data.len() < 4 + len {
664            return None;
665        }
666        let s = String::from_utf8(data[4..4 + len].to_vec()).ok()?;
667        Some((s, 4 + len))
668    }
669
670    /// Read bytecode
671    fn read_bytecode(data: &[u8]) -> Option<(Bytecode, usize)> {
672        let mut offset = 0;
673
674        // Sources
675        if data.len() < 4 {
676            return None;
677        }
678        let source_count = u32::from_le_bytes(data[0..4].try_into().ok()?) as usize;
679        offset += 4;
680
681        let mut sources = Vec::with_capacity(source_count);
682        for _ in 0..source_count {
683            let (inst, len) = Self::read_instruction(&data[offset..])?;
684            offset += len;
685            sources.push(inst);
686        }
687
688        // Steps
689        if data.len() < offset + 4 {
690            return None;
691        }
692        let step_count = u32::from_le_bytes(data[offset..offset + 4].try_into().ok()?) as usize;
693        offset += 4;
694
695        let mut steps = Vec::with_capacity(step_count);
696        for _ in 0..step_count {
697            let (inst, len) = Self::read_instruction(&data[offset..])?;
698            offset += len;
699            steps.push(inst);
700        }
701
702        Some((Bytecode { sources, steps }, offset))
703    }
704
705    /// Read single instruction
706    fn read_instruction(data: &[u8]) -> Option<(Instruction, usize)> {
707        let mut offset = 0;
708
709        let (name, len) = Self::read_string(data)?;
710        offset += len;
711
712        if data.len() < offset + 4 {
713            return None;
714        }
715        let arg_count = u32::from_le_bytes(data[offset..offset + 4].try_into().ok()?) as usize;
716        offset += 4;
717
718        let mut args = Vec::with_capacity(arg_count);
719        for _ in 0..arg_count {
720            let (arg, len) = Self::read_value(&data[offset..])?;
721            offset += len;
722            args.push(arg);
723        }
724
725        Some((Instruction::new(name, args), offset))
726    }
727}
728
729#[cfg(test)]
730mod tests {
731    use super::*;
732
733    #[test]
734    fn test_type_code_roundtrip() {
735        for code in [
736            TypeCode::Int32,
737            TypeCode::Int64,
738            TypeCode::String,
739            TypeCode::List,
740            TypeCode::Null,
741        ] {
742            assert_eq!(TypeCode::from_byte(code as u8), Some(code));
743        }
744    }
745
746    #[test]
747    fn test_serialize_int32() {
748        let value = BinaryValue::Int32(42);
749        let bytes = BinarySerializer::serialize(&value);
750
751        let (decoded, _) = BinaryDeserializer::deserialize(&bytes).unwrap();
752        match decoded {
753            BinaryValue::Int32(i) => assert_eq!(i, 42),
754            _ => panic!("Expected Int32"),
755        }
756    }
757
758    #[test]
759    fn test_serialize_string() {
760        let value = BinaryValue::String("hello".to_string());
761        let bytes = BinarySerializer::serialize(&value);
762
763        let (decoded, _) = BinaryDeserializer::deserialize(&bytes).unwrap();
764        match decoded {
765            BinaryValue::String(s) => assert_eq!(s, "hello"),
766            _ => panic!("Expected String"),
767        }
768    }
769
770    #[test]
771    fn test_serialize_list() {
772        let value = BinaryValue::List(vec![
773            BinaryValue::Int32(1),
774            BinaryValue::Int32(2),
775            BinaryValue::Int32(3),
776        ]);
777        let bytes = BinarySerializer::serialize(&value);
778
779        let (decoded, _) = BinaryDeserializer::deserialize(&bytes).unwrap();
780        match decoded {
781            BinaryValue::List(items) => {
782                assert_eq!(items.len(), 3);
783            }
784            _ => panic!("Expected List"),
785        }
786    }
787
788    #[test]
789    fn test_serialize_null() {
790        let value = BinaryValue::Null;
791        let bytes = BinarySerializer::serialize(&value);
792
793        let (decoded, _) = BinaryDeserializer::deserialize(&bytes).unwrap();
794        assert!(decoded.is_null());
795    }
796
797    #[test]
798    fn test_serialize_traverser() {
799        let value = BinaryValue::Traverser {
800            value: Box::new(BinaryValue::String("vertex1".to_string())),
801            bulk: 5,
802        };
803        let bytes = BinarySerializer::serialize(&value);
804
805        let (decoded, _) = BinaryDeserializer::deserialize(&bytes).unwrap();
806        match decoded {
807            BinaryValue::Traverser { bulk, .. } => assert_eq!(bulk, 5),
808            _ => panic!("Expected Traverser"),
809        }
810    }
811
812    #[test]
813    fn test_bytecode_serialization() {
814        let mut bc = Bytecode::new();
815        bc.add_source("V", vec![]);
816        bc.add_step("out", vec![BinaryValue::String("knows".to_string())]);
817        bc.add_step(
818            "has",
819            vec![
820                BinaryValue::String("name".to_string()),
821                BinaryValue::String("alice".to_string()),
822            ],
823        );
824
825        let value = BinaryValue::Bytecode(bc);
826        let bytes = BinarySerializer::serialize(&value);
827
828        let (decoded, _) = BinaryDeserializer::deserialize(&bytes).unwrap();
829        match decoded {
830            BinaryValue::Bytecode(bc) => {
831                assert_eq!(bc.sources.len(), 1);
832                assert_eq!(bc.steps.len(), 2);
833                assert_eq!(bc.sources[0].name, "V");
834                assert_eq!(bc.steps[0].name, "out");
835                assert_eq!(bc.steps[1].name, "has");
836            }
837            _ => panic!("Expected Bytecode"),
838        }
839    }
840
841    #[test]
842    fn test_type_info() {
843        let info = TypeInfo::new("MyCustomType", 1);
844        let bytes = info.to_bytes();
845
846        let (decoded, _) = TypeInfo::from_bytes(&bytes).unwrap();
847        assert_eq!(decoded.name, "MyCustomType");
848        assert_eq!(decoded.version, 1);
849    }
850}