@@ -19,17 +19,25 @@ mod root {
19
19
20
20
/// An item returned by `iter_root_chunks`, allowing access to the `data` stored alongside nodes in a [`Tree`].
21
21
pub ( crate ) struct Node < ' a , T : Send > {
22
+ // SAFETY INVARIANT: see Node::new(). That function is the only one used
23
+ // to create or modify these fields.
22
24
item : & ' a mut Item < T > ,
23
25
child_items : & ' a ItemSliceSync < ' a , Item < T > > ,
24
26
}
25
27
26
28
impl < ' a , T : Send > Node < ' a , T > {
27
- /// SAFETY: The child_items must be unique among between users of the `ItemSliceSync`.
29
+ /// SAFETY: `item.children` must uniquely reference elements in child_items that no other currently alive
30
+ /// item does. All child_items must also have unique children, unless the child_item is itself `item`,
31
+ /// in which case no other live item should reference it in its `item.children`.
32
+ ///
33
+ /// This safety invariant can be reliably upheld by making sure `item` comes from a Tree and `child_items`
34
+ /// was constructed using that Tree's child_items. This works since Tree has this invariant as well: all
35
+ /// child_items are referenced at most once (really, exactly once) by a node in the tree.
36
+ ///
37
+ /// Note that this invariant is a bit more relaxed than that on `deltas()`, because this function can be called
38
+ /// for traversal within a child item, which happens in into_child_iter()
28
39
#[ allow( unsafe_code) ]
29
- pub ( in crate :: cache:: delta:: traverse) unsafe fn new (
30
- item : & ' a mut Item < T > ,
31
- child_items : & ' a ItemSliceSync < ' a , Item < T > > ,
32
- ) -> Self {
40
+ pub ( super ) unsafe fn new ( item : & ' a mut Item < T > , child_items : & ' a ItemSliceSync < ' a , Item < T > > ) -> Self {
33
41
Node { item, child_items }
34
42
}
35
43
}
@@ -60,18 +68,20 @@ mod root {
60
68
/// Children are `Node`s referring to pack entries whose base object is this pack entry.
61
69
pub fn into_child_iter ( self ) -> impl Iterator < Item = Node < ' a , T > > + ' a {
62
70
let children = self . child_items ;
63
- // SAFETY: The index is a valid index into the children array.
64
- // SAFETY: The resulting mutable pointer cannot be yielded by any other node.
65
71
#[ allow( unsafe_code) ]
66
- self . item . children . iter ( ) . map ( move |& index| Node {
67
- item : unsafe { children. get_mut ( index as usize ) } ,
68
- child_items : children,
72
+ self . item . children . iter ( ) . map ( move |& index| {
73
+ // SAFETY: Due to the invariant on new(), we can rely on these indices
74
+ // being unique.
75
+ let item = unsafe { children. get_mut ( index as usize ) } ;
76
+ // SAFETY: Since every child_item is also required to uphold the uniqueness guarantee,
77
+ // creating a Node with one of the child_items that we are allowed access to is still fine.
78
+ unsafe { Node :: new ( item, children) }
69
79
} )
70
80
}
71
81
}
72
82
}
73
83
74
- pub ( in crate :: cache :: delta :: traverse ) struct State < ' items , F , MBFN , T : Send > {
84
+ pub ( super ) struct State < ' items , F , MBFN , T : Send > {
75
85
pub delta_bytes : Vec < u8 > ,
76
86
pub fully_resolved_delta_bytes : Vec < u8 > ,
77
87
pub progress : Box < dyn Progress > ,
@@ -80,8 +90,15 @@ pub(in crate::cache::delta::traverse) struct State<'items, F, MBFN, T: Send> {
80
90
pub child_items : & ' items ItemSliceSync < ' items , Item < T > > ,
81
91
}
82
92
83
- #[ allow( clippy:: too_many_arguments) ]
84
- pub ( in crate :: cache:: delta:: traverse) fn deltas < T , F , MBFN , E , R > (
93
+ /// SAFETY: `item.children` must uniquely reference elements in child_items that no other currently alive
94
+ /// item does. All child_items must also have unique children.
95
+ ///
96
+ /// This safety invariant can be reliably upheld by making sure `item` comes from a Tree and `child_items`
97
+ /// was constructed using that Tree's child_items. This works since Tree has this invariant as well: all
98
+ /// child_items are referenced at most once (really, exactly once) by a node in the tree.
99
+ #[ allow( clippy:: too_many_arguments, unsafe_code) ]
100
+ #[ deny( unsafe_op_in_unsafe_fn) ] // this is a big function, require unsafe for the one small unsafe op we have
101
+ pub ( super ) unsafe fn deltas < T , F , MBFN , E , R > (
85
102
objects : gix_features:: progress:: StepShared ,
86
103
size : gix_features:: progress:: StepShared ,
87
104
item : & mut Item < T > ,
@@ -121,7 +138,7 @@ where
121
138
// each node is a base, and its children always start out as deltas which become a base after applying them.
122
139
// These will be pushed onto our stack until all are processed
123
140
let root_level = 0 ;
124
- // SAFETY: The child items are unique, as `item` is the root of a tree of dependent child items.
141
+ // SAFETY: This invariant is required from the caller
125
142
#[ allow( unsafe_code) ]
126
143
let root_node = unsafe { root:: Node :: new ( item, child_items) } ;
127
144
let mut nodes: Vec < _ > = vec ! [ ( root_level, root_node) ] ;
0 commit comments