@@ -47,7 +47,12 @@ mod imp {
4747 /// Get a reference to the ingredient in the database.
4848 ///
4949 /// If the ingredient index is not already in the cache, it will be loaded and cached.
50- pub fn get_or_create < ' db > (
50+ ///
51+ /// # Safety
52+ ///
53+ /// The `IngredientIndex` returned by the closure must reference a valid ingredient of
54+ /// type `I` in the provided zalsa database.
55+ pub unsafe fn get_or_create < ' db > (
5156 & self ,
5257 zalsa : & ' db Zalsa ,
5358 load_index : impl Fn ( ) -> IngredientIndex ,
@@ -57,9 +62,21 @@ mod imp {
5762 ingredient_index = self . get_or_create_index_slow ( load_index) . as_u32 ( ) ;
5863 } ;
5964
60- zalsa
61- . lookup_ingredient ( IngredientIndex :: from_unchecked ( ingredient_index) )
62- . assert_type ( )
65+ // SAFETY: `ingredient_index` is initialized from a valid `IngredientIndex`.
66+ let ingredient_index = unsafe { IngredientIndex :: new_unchecked ( ingredient_index) } ;
67+
68+ // SAFETY: There are a two cases here:
69+ // - The `create_index` closure was called due to the data being uncached. In this
70+ // case, the caller guarantees the index is in-bounds and has the correct type.
71+ // - The index was cached. While the current database might not be the same database
72+ // the ingredient was initially loaded from, the `inventory` feature is enabled, so
73+ // ingredient indices are stable across databases. Thus the index is still in-bounds
74+ // and has the correct type.
75+ unsafe {
76+ zalsa
77+ . lookup_ingredient_unchecked ( ingredient_index)
78+ . assert_type_unchecked ( )
79+ }
6380 }
6481
6582 #[ cold]
@@ -134,14 +151,30 @@ mod imp {
134151 /// Get a reference to the ingredient in the database.
135152 ///
136153 /// If the ingredient is not already in the cache, it will be created.
154+ ///
155+ /// # Safety
156+ ///
157+ /// The `IngredientIndex` returned by the closure must reference a valid ingredient of
158+ /// type `I` in the provided zalsa database.
137159 #[ inline( always) ]
138- pub fn get_or_create < ' db > (
160+ pub unsafe fn get_or_create < ' db > (
139161 & self ,
140162 zalsa : & ' db Zalsa ,
141163 create_index : impl Fn ( ) -> IngredientIndex ,
142164 ) -> & ' db I {
143165 let index = self . get_or_create_index ( zalsa, create_index) ;
144- zalsa. lookup_ingredient ( index) . assert_type :: < I > ( )
166+
167+ // SAFETY: There are a two cases here:
168+ // - The `create_index` closure was called due to the data being uncached for the
169+ // provided database. In this case, the caller guarantees the index is in-bounds
170+ // and has the correct type.
171+ // - We verified the index was cached for the same database, by the nonce check.
172+ // Thus the initial safety argument still applies.
173+ unsafe {
174+ zalsa
175+ . lookup_ingredient_unchecked ( index)
176+ . assert_type_unchecked :: < I > ( )
177+ }
145178 }
146179
147180 pub fn get_or_create_index (
@@ -159,7 +192,9 @@ mod imp {
159192 } ;
160193
161194 // Unpack our `u64` into the nonce and index.
162- let index = IngredientIndex :: from_unchecked ( cached_data as u32 ) ;
195+ //
196+ // SAFETY: The lower bits of `cached_data` are initialized from a valid `IngredientIndex`.
197+ let index = unsafe { IngredientIndex :: new_unchecked ( cached_data as u32 ) } ;
163198
164199 // SAFETY: We've checked against `UNINITIALIZED` (0) above and so the upper bits must be non-zero.
165200 let nonce = crate :: nonce:: Nonce :: < StorageNonce > :: from_u32 ( unsafe {
0 commit comments