1919use crate :: types:: id:: { RecordId , NodeId , EdgeId } ;
2020use crate :: types:: vector:: FxpVector ;
2121use crate :: types:: enums:: { NodeKind , EdgeKind } ;
22- use serde:: { Serialize , Deserialize } ;
22+ use serde:: { Serialize , Deserialize , Serializer , Deserializer } ;
23+ use serde:: ser:: { SerializeStruct , SerializeStructVariant } ;
24+ use serde:: de:: { self , Visitor , MapAccess , SeqAccess , EnumAccess , VariantAccess } ;
25+ use core:: fmt;
2326
2427/// KernelEvent represents the canonical event language for Valori.
2528/// This is the ONLY way to express state transitions.
2629///
2730/// Each variant represents an atomic, deterministic operation on the kernel state.
28- #[ derive( Clone , Debug , Serialize , Deserialize , PartialEq , Eq ) ]
31+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
2932pub enum KernelEvent < const D : usize > {
3033 /// Insert a new vector record into the kernel
3134 InsertRecord {
3235 id : RecordId ,
3336 vector : FxpVector < D > ,
37+ metadata : Option < alloc:: vec:: Vec < u8 > > ,
3438 } ,
3539
3640 /// Delete an existing vector record from the kernel
@@ -72,6 +76,172 @@ impl<const D: usize> KernelEvent<D> {
7276 }
7377}
7478
79+ // Custom Serialization to support strict V2 Metadata format
80+ impl < const D : usize > Serialize for KernelEvent < D > {
81+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
82+ where
83+ S : Serializer ,
84+ {
85+ match self {
86+ KernelEvent :: InsertRecord { id, vector, metadata } => {
87+ // We serialize as a struct variant with 3 fields for Serialize
88+ // But specifically for metadata, we manually encode the length + bytes
89+ // To achieve "No version flag", we just write the fields.
90+ // Bincode enum serialization: [VariantIdx][Field1][Field2][...]
91+ let mut state = serializer. serialize_struct_variant ( "KernelEvent" , 0 , "InsertRecord" , 3 ) ?;
92+ state. serialize_field ( "id" , id) ?;
93+ state. serialize_field ( "vector" , vector) ?;
94+
95+ // Custom Metadata Serialization: u32 Len + Bytes
96+ // We wrap this in a helper or just serialize a "RawMetadata" struct
97+ let meta_wrapper = RawMetadata ( metadata. as_ref ( ) ) ;
98+ state. serialize_field ( "metadata" , & meta_wrapper) ?;
99+
100+ state. end ( )
101+ }
102+ KernelEvent :: DeleteRecord { id } => {
103+ let mut state = serializer. serialize_struct_variant ( "KernelEvent" , 1 , "DeleteRecord" , 1 ) ?;
104+ state. serialize_field ( "id" , id) ?;
105+ state. end ( )
106+ }
107+ KernelEvent :: CreateNode { id, kind, record } => {
108+ let mut state = serializer. serialize_struct_variant ( "KernelEvent" , 2 , "CreateNode" , 3 ) ?;
109+ state. serialize_field ( "id" , id) ?;
110+ state. serialize_field ( "kind" , kind) ?;
111+ state. serialize_field ( "record" , record) ?;
112+ state. end ( )
113+ }
114+ KernelEvent :: CreateEdge { id, from, to, kind } => {
115+ let mut state = serializer. serialize_struct_variant ( "KernelEvent" , 3 , "CreateEdge" , 4 ) ?;
116+ state. serialize_field ( "id" , id) ?;
117+ state. serialize_field ( "from" , from) ?;
118+ state. serialize_field ( "to" , to) ?;
119+ state. serialize_field ( "kind" , kind) ?;
120+ state. end ( )
121+ }
122+ KernelEvent :: DeleteEdge { id } => {
123+ let mut state = serializer. serialize_struct_variant ( "KernelEvent" , 4 , "DeleteEdge" , 1 ) ?;
124+ state. serialize_field ( "id" , id) ?;
125+ state. end ( )
126+ }
127+ }
128+ }
129+ }
130+
131+ struct RawMetadata < ' a > ( Option < & ' a alloc:: vec:: Vec < u8 > > ) ;
132+
133+ impl < ' a > Serialize for RawMetadata < ' a > {
134+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
135+ where S : Serializer {
136+ match self . 0 {
137+ Some ( bytes) => {
138+ let len = bytes. len ( ) as u32 ;
139+ // We can't write two fields here easily if we are just one field in the parent struct?
140+ // Actually Bincode flattens structs.
141+ // So if we serialize as a tuple `(len, bytes)`, it writes [len][bytes].
142+ ( len, bytes) . serialize ( serializer)
143+ }
144+ None => {
145+ let len: u32 = 0 ;
146+ // Write 0 length, no bytes.
147+ len. serialize ( serializer)
148+ }
149+ }
150+ }
151+ }
152+
153+ // Custom Deserialization
154+ impl < ' de , const D : usize > Deserialize < ' de > for KernelEvent < D > {
155+ fn deserialize < Deser > ( deserializer : Deser ) -> Result < Self , Deser :: Error >
156+ where
157+ Deser : Deserializer < ' de > ,
158+ {
159+ // Use a Shadow Enum that matches the structure but uses a custom type for Metadata
160+ // This allows us to intercept the metadata deserialization for backward compatibility logic
161+ #[ derive( Serialize , Deserialize ) ]
162+ enum KernelEventHelper < const D : usize > {
163+ InsertRecord {
164+ id : RecordId ,
165+ vector : FxpVector < D > ,
166+ #[ serde( with = "raw_metadata_serde" ) ]
167+ metadata : Option < alloc:: vec:: Vec < u8 > > ,
168+ } ,
169+ DeleteRecord {
170+ id : RecordId ,
171+ } ,
172+ CreateNode {
173+ id : NodeId ,
174+ kind : NodeKind ,
175+ record : Option < RecordId > ,
176+ } ,
177+ CreateEdge {
178+ id : EdgeId ,
179+ from : NodeId ,
180+ to : NodeId ,
181+ kind : EdgeKind ,
182+ } ,
183+ DeleteEdge {
184+ id : EdgeId ,
185+ } ,
186+ }
187+
188+ // Delegate to the Helper
189+ let helper = KernelEventHelper :: < D > :: deserialize ( deserializer) ?;
190+
191+ Ok ( match helper {
192+ KernelEventHelper :: InsertRecord { id, vector, metadata } => KernelEvent :: InsertRecord { id, vector, metadata } ,
193+ KernelEventHelper :: DeleteRecord { id } => KernelEvent :: DeleteRecord { id } ,
194+ KernelEventHelper :: CreateNode { id, kind, record } => KernelEvent :: CreateNode { id, kind, record } ,
195+ KernelEventHelper :: CreateEdge { id, from, to, kind } => KernelEvent :: CreateEdge { id, from, to, kind } ,
196+ KernelEventHelper :: DeleteEdge { id } => KernelEvent :: DeleteEdge { id } ,
197+ } )
198+ }
199+ }
200+
201+ mod raw_metadata_serde {
202+ use super :: * ;
203+ use serde:: { Serializer , Deserializer } ;
204+
205+ pub fn serialize < S > ( metadata : & Option < alloc:: vec:: Vec < u8 > > , serializer : S ) -> Result < S :: Ok , S :: Error >
206+ where S : Serializer {
207+ match metadata {
208+ Some ( bytes) => {
209+ let len = bytes. len ( ) as u32 ;
210+ ( len, bytes) . serialize ( serializer)
211+ }
212+ None => {
213+ let len: u32 = 0 ;
214+ len. serialize ( serializer)
215+ }
216+ }
217+ }
218+
219+ pub fn deserialize < ' de , D > ( deserializer : D ) -> Result < Option < alloc:: vec:: Vec < u8 > > , D :: Error >
220+ where D : Deserializer < ' de > {
221+ struct MetadataVisitor ;
222+ impl < ' de > Visitor < ' de > for MetadataVisitor {
223+ type Value = Option < alloc:: vec:: Vec < u8 > > ;
224+ fn expecting ( & self , formatter : & mut fmt:: Formatter ) -> fmt:: Result {
225+ formatter. write_str ( "metadata length and bytes" )
226+ }
227+
228+ fn visit_seq < A > ( self , mut seq : A ) -> Result < Self :: Value , A :: Error >
229+ where A : SeqAccess < ' de > {
230+ let len: u32 = seq. next_element ( ) ?. ok_or_else ( || de:: Error :: invalid_length ( 0 , & self ) ) ?;
231+
232+ if len == 0 {
233+ return Ok ( None ) ;
234+ }
235+
236+ let bytes: alloc:: vec:: Vec < u8 > = seq. next_element ( ) ?. ok_or_else ( || de:: Error :: invalid_length ( 1 , & self ) ) ?;
237+ Ok ( Some ( bytes) )
238+ }
239+ }
240+
241+ deserializer. deserialize_tuple ( 2 , MetadataVisitor )
242+ }
243+ }
244+
75245#[ cfg( test) ]
76246mod tests {
77247 use super :: * ;
@@ -82,6 +252,7 @@ mod tests {
82252 let event = KernelEvent :: < 16 > :: InsertRecord {
83253 id : RecordId ( 42 ) ,
84254 vector : FxpVector :: new_zeros ( ) ,
255+ metadata : Some ( alloc:: vec![ 0xAA , 0xBB ] ) ,
85256 } ;
86257
87258 let bytes1 = bincode:: serde:: encode_to_vec ( & event, bincode:: config:: standard ( ) ) . unwrap ( ) ;
0 commit comments