@@ -11,7 +11,9 @@ use crate::{
11
11
} ;
12
12
use spacetimedb_sats:: {
13
13
algebraic_value:: { ser:: ValueSerializer , Packed } ,
14
- i256, u256, AlgebraicType , AlgebraicValue , ArrayValue , ProductType , ProductValue , SumValue ,
14
+ i256,
15
+ sum_value:: SumTag ,
16
+ u256, AlgebraicType , AlgebraicValue , ArrayValue , ProductType , ProductValue , SumValue ,
15
17
} ;
16
18
use std:: { cell:: Cell , mem} ;
17
19
use thiserror:: Error ;
@@ -339,6 +341,29 @@ impl_read_column_via_from! {
339
341
i256 => Box <i256>;
340
342
}
341
343
344
+ /// SAFETY: `is_compatible_type` only returns true for sum types,
345
+ /// and any sum value stores the tag first in BFLATN.
346
+ unsafe impl ReadColumn for SumTag {
347
+ fn is_compatible_type ( ty : & AlgebraicTypeLayout ) -> bool {
348
+ matches ! ( ty, AlgebraicTypeLayout :: Sum ( _) )
349
+ }
350
+
351
+ unsafe fn unchecked_read_column ( row_ref : RowRef < ' _ > , layout : & ProductTypeElementLayout ) -> Self {
352
+ debug_assert ! ( Self :: is_compatible_type( & layout. ty) ) ;
353
+
354
+ let ( page, offset) = row_ref. page_and_offset ( ) ;
355
+ let col_offset = offset + PageOffset ( layout. offset ) ;
356
+
357
+ let data = page. get_row_data ( col_offset, Size ( 1 ) ) ;
358
+ let data: Result < [ u8 ; 1 ] , _ > = data. try_into ( ) ;
359
+ // SAFETY: `<[u8; 1] as TryFrom<&[u8]>` succeeds if and only if the slice's length is `1`.
360
+ // We used `1` as both the length of the slice and the array, so we know them to be equal.
361
+ let [ data] = unsafe { data. unwrap_unchecked ( ) } ;
362
+
363
+ Self ( data)
364
+ }
365
+ }
366
+
342
367
#[ cfg( test) ]
343
368
mod test {
344
369
use super :: * ;
@@ -512,5 +537,21 @@ mod test {
512
537
513
538
// Use a long string which will hit the blob store.
514
539
read_column_long_string { AlgebraicType :: String => Box <str > = "long string. " . repeat( 2048 ) . into( ) } ;
540
+
541
+ read_sum_value_plain { AlgebraicType :: simple_enum( [ "a" , "b" ] . into_iter( ) ) => SumValue = SumValue :: new_simple( 1 ) } ;
542
+ read_sum_tag_plain { AlgebraicType :: simple_enum( [ "a" , "b" ] . into_iter( ) ) => SumTag = SumTag ( 1 ) } ;
543
+ }
544
+
545
+ #[ test]
546
+ fn read_sum_tag_from_sum_with_payload ( ) {
547
+ let algebraic_type = AlgebraicType :: sum ( [ ( "a" , AlgebraicType :: U8 ) , ( "b" , AlgebraicType :: U16 ) ] ) ;
548
+
549
+ let mut blob_store = HashMapBlobStore :: default ( ) ;
550
+ let mut table = table ( ProductType :: from ( [ algebraic_type] ) ) ;
551
+
552
+ let val = SumValue :: new ( 1 , 42u16 ) ;
553
+ let ( _, row_ref) = table. insert ( & mut blob_store, & product ! [ val. clone( ) ] ) . unwrap ( ) ;
554
+
555
+ assert_eq ! ( val. tag, row_ref. read_col:: <SumTag >( 0 ) . unwrap( ) . 0 ) ;
515
556
}
516
557
}
0 commit comments