@@ -562,3 +562,137 @@ fn object_insert_returns_previous_value() {
562562 assert_eq ! ( obj. insert( val( 0 ) , val( 2 ) ) , Some ( val( 1 ) ) ) ;
563563 assert_eq ! ( obj. get( & val( 0 ) ) , Some ( & val( 2 ) ) ) ;
564564}
565+
566+ const CONST_OBJECT_NEW : Object = Object :: new ( ) ;
567+
568+ fn assert_all_objects_frozen ( value : & Value ) {
569+ match value {
570+ Value :: Array ( values) => {
571+ for value in values. iter ( ) {
572+ assert_all_objects_frozen ( value) ;
573+ }
574+ }
575+ Value :: Set ( values) => {
576+ for value in values. iter ( ) {
577+ assert_all_objects_frozen ( value) ;
578+ }
579+ }
580+ Value :: Object ( object) => {
581+ assert_eq ! ( object. storage_variant_for_memory_diagnostics( ) , "Frozen" ) ;
582+ for ( _, value) in object. iter ( ) {
583+ assert_all_objects_frozen ( value) ;
584+ }
585+ }
586+ _ => { }
587+ }
588+ }
589+
590+ #[ test]
591+ fn object_new_is_const_context ( ) {
592+ assert ! ( CONST_OBJECT_NEW . is_empty( ) ) ;
593+ }
594+
595+ #[ test]
596+ fn object_inline_cap_boundary_promotes_on_third_insert ( ) {
597+ let mut obj = Object :: new ( ) ;
598+ obj. insert ( val ( 1 ) , val ( 10 ) ) ;
599+ obj. insert ( val ( 2 ) , val ( 20 ) ) ;
600+ assert_eq ! ( obj. storage_variant_for_memory_diagnostics( ) , "Inline" ) ;
601+ obj. insert ( val ( 3 ) , val ( 30 ) ) ;
602+ assert_eq ! ( obj. storage_variant_for_memory_diagnostics( ) , "BTree" ) ;
603+ }
604+
605+ #[ test]
606+ fn object_btree_freeze_mutate_insert_and_refreeze_roundtrip ( ) {
607+ let mut obj: Object = make_pairs ( 3 ) . into_iter ( ) . collect ( ) ;
608+ assert_eq ! ( obj. storage_variant_for_memory_diagnostics( ) , "BTree" ) ;
609+ obj = obj. freeze ( ) ;
610+ assert_eq ! ( obj. storage_variant_for_memory_diagnostics( ) , "Frozen" ) ;
611+ obj. insert ( val ( 99 ) , val ( 100 ) ) ;
612+ assert_eq ! ( obj. storage_variant_for_memory_diagnostics( ) , "BTree" ) ;
613+ assert_eq ! ( obj. get( & val( 99 ) ) , Some ( & val( 100 ) ) ) ;
614+ obj = obj. freeze ( ) ;
615+ assert_eq ! ( obj. storage_variant_for_memory_diagnostics( ) , "Frozen" ) ;
616+ assert_eq ! ( obj. get( & val( 99 ) ) , Some ( & val( 100 ) ) ) ;
617+ }
618+
619+ #[ test]
620+ fn object_empty_freeze_get_iter_and_cursor ( ) {
621+ let obj = Object :: new ( ) . freeze ( ) ;
622+ assert_eq ! ( obj. storage_variant_for_memory_diagnostics( ) , "Frozen" ) ;
623+ assert ! ( obj. get( & val( 0 ) ) . is_none( ) ) ;
624+ assert_eq ! ( obj. iter( ) . count( ) , 0 ) ;
625+ let mut cursor = obj. cursor ( ) ;
626+ assert ! ( obj. next( & mut cursor) . is_none( ) ) ;
627+ }
628+
629+ #[ test]
630+ fn object_from_large_btreemap_into_value_is_frozen ( ) {
631+ let map: BTreeMap < Value , Value > = make_pairs ( 3 ) . into_iter ( ) . collect ( ) ;
632+ let value = Object :: from ( map) . into_value ( ) ;
633+ let object = value. as_object ( ) . expect ( "object" ) ;
634+ assert_eq ! ( object. storage_variant_for_memory_diagnostics( ) , "Frozen" ) ;
635+ }
636+
637+ #[ test]
638+ fn object_cross_variant_partial_eq_ignores_storage ( ) {
639+ let empty_inline = Object :: from_iter ( core:: iter:: empty ( ) ) . freeze ( ) ;
640+ assert_eq ! ( Object :: new( ) , empty_inline) ;
641+
642+ let inline: Object = make_pairs ( 2 ) . into_iter ( ) . collect ( ) ;
643+ assert_eq ! ( inline. storage_variant_for_memory_diagnostics( ) , "Inline" ) ;
644+ let frozen = inline. clone ( ) . freeze ( ) ;
645+
646+ let mut btree: Object = make_pairs ( 3 ) . into_iter ( ) . collect ( ) ;
647+ btree. remove ( & val ( 2 ) ) ;
648+ assert_eq ! ( btree. storage_variant_for_memory_diagnostics( ) , "BTree" ) ;
649+
650+ assert_eq ! ( inline, frozen) ;
651+ assert_eq ! ( inline, btree) ;
652+ }
653+
654+ #[ test]
655+ fn object_cursor_frozen_one_entry_yields_once ( ) {
656+ let obj = Object :: from_iter ( [ ( val ( 1 ) , val ( 2 ) ) ] ) . freeze ( ) ;
657+ let mut cursor = obj. cursor ( ) ;
658+ assert_eq ! ( obj. next( & mut cursor) , Some ( ( & val( 1 ) , & val( 2 ) ) ) ) ;
659+ assert ! ( obj. next( & mut cursor) . is_none( ) ) ;
660+ }
661+
662+ #[ test]
663+ fn object_iter_mut_on_frozen_persists_changes ( ) {
664+ let mut obj = Object :: from_iter ( [ ( val ( 1 ) , val ( 2 ) ) ] ) . freeze ( ) ;
665+ for ( _, value) in obj. iter_mut ( ) {
666+ * value = val ( 3 ) ;
667+ }
668+ assert_eq ! ( obj. get( & val( 1 ) ) , Some ( & val( 3 ) ) ) ;
669+ }
670+
671+ #[ test]
672+ fn value_freeze_recursive_freezes_nested_objects ( ) {
673+ let mut inner = Object :: new ( ) ;
674+ inner. insert ( val ( 1 ) , val ( 2 ) ) ;
675+
676+ let mut set = alloc:: collections:: BTreeSet :: new ( ) ;
677+ set. insert ( inner. clone ( ) . into_value ( ) ) ;
678+
679+ let mut outer = Object :: new ( ) ;
680+ outer. insert (
681+ Value :: from ( "array" ) ,
682+ Value :: from ( Vec :: from ( [ inner. into_value ( ) ] ) ) ,
683+ ) ;
684+ outer. insert ( Value :: from ( "set" ) , Value :: from ( set) ) ;
685+
686+ let mut value = outer. into_value ( ) ;
687+ value. freeze_recursive ( ) ;
688+ assert_all_objects_frozen ( & value) ;
689+ }
690+
691+ #[ test]
692+ fn object_hybrid_insert_existing_on_frozen_stays_frozen ( ) {
693+ let mut obj = Object :: from_iter ( [ ( val ( 1 ) , val ( 2 ) ) ] ) . freeze ( ) ;
694+ assert_eq ! ( obj. storage_variant_for_memory_diagnostics( ) , "Frozen" ) ;
695+ assert_eq ! ( obj. insert( val( 1 ) , val( 9 ) ) , Some ( val( 2 ) ) ) ;
696+ assert_eq ! ( obj. storage_variant_for_memory_diagnostics( ) , "Frozen" ) ;
697+ assert_eq ! ( obj. get( & val( 1 ) ) , Some ( & val( 9 ) ) ) ;
698+ }
0 commit comments