/rust/registry/src/index.crates.io-1949cf8c6b5b557f/intrusive-collections-0.9.6/src/adapter.rs
Line | Count | Source |
1 | | // Copyright 2016 Amanieu d'Antras |
2 | | // Copyright 2020 Amari Robinson |
3 | | // |
4 | | // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or |
5 | | // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or |
6 | | // http://opensource.org/licenses/MIT>, at your option. This file may not be |
7 | | // copied, modified, or distributed except according to those terms. |
8 | | |
9 | | use crate::link_ops::LinkOps; |
10 | | use crate::pointer_ops::PointerOps; |
11 | | |
12 | | /// Trait for a adapter which allows a type to be inserted into an intrusive |
13 | | /// collection. |
14 | | /// |
15 | | /// `LinkOps` implements the collection-specific operations which |
16 | | /// allows an object to be inserted into an intrusive collection. This type |
17 | | /// needs to implement the appropriate trait for the collection type |
18 | | /// (eg. `LinkedListOps` for inserting into a `LinkedList`). |
19 | | /// `LinkOps` type may be stateful, allowing custom link types. |
20 | | /// |
21 | | /// `PointerOps` implements the collection-specific pointer conversions which |
22 | | /// allow an object to be inserted into an intrusive collection. |
23 | | /// `PointerOps` type may be stateful, allowing custom pointer types. |
24 | | /// |
25 | | /// A single object type may have multiple adapters, which allows it to be part |
26 | | /// of multiple intrusive collections simultaneously. |
27 | | /// |
28 | | /// In most cases you do not need to implement this trait manually: the |
29 | | /// `intrusive_adapter!` macro will generate the necessary implementation for a |
30 | | /// given type and its link field. However it is possible to implement it |
31 | | /// manually if the intrusive link is not a direct field of the object type. |
32 | | /// |
33 | | /// It is also possible to create stateful adapters. |
34 | | /// This allows links and containers to be separated and avoids the need for objects to be modified to |
35 | | /// contain a link. |
36 | | /// |
37 | | /// # Safety |
38 | | /// |
39 | | /// It must be possible to get back a reference to the container by passing a |
40 | | /// pointer returned by `get_link` to `get_container`. |
41 | | pub unsafe trait Adapter { |
42 | | /// Collection-specific link operations which allow an object to be inserted in |
43 | | /// an intrusive collection. |
44 | | type LinkOps: LinkOps; |
45 | | |
46 | | /// Collection-specific pointer conversions which allow an object to |
47 | | /// be inserted in an intrusive collection. |
48 | | type PointerOps: PointerOps; |
49 | | |
50 | | /// Gets a reference to an object from a reference to a link in that object. |
51 | | /// |
52 | | /// # Safety |
53 | | /// |
54 | | /// `link` must be a valid pointer previously returned by `get_link`. |
55 | | unsafe fn get_value( |
56 | | &self, |
57 | | link: <Self::LinkOps as LinkOps>::LinkPtr, |
58 | | ) -> *const <Self::PointerOps as PointerOps>::Value; |
59 | | |
60 | | /// Gets a reference to the link for the given object. |
61 | | /// |
62 | | /// # Safety |
63 | | /// |
64 | | /// `value` must be a valid pointer. |
65 | | unsafe fn get_link( |
66 | | &self, |
67 | | value: *const <Self::PointerOps as PointerOps>::Value, |
68 | | ) -> <Self::LinkOps as LinkOps>::LinkPtr; |
69 | | |
70 | | /// Returns a reference to the link operations. |
71 | | fn link_ops(&self) -> &Self::LinkOps; |
72 | | |
73 | | /// Returns a reference to the mutable link operations. |
74 | | fn link_ops_mut(&mut self) -> &mut Self::LinkOps; |
75 | | |
76 | | /// Returns a reference to the pointer converter. |
77 | | fn pointer_ops(&self) -> &Self::PointerOps; |
78 | | } |
79 | | |
80 | | /// Unsafe macro to get a raw pointer to an outer object from a pointer to one |
81 | | /// of its fields. |
82 | | /// |
83 | | /// # Examples |
84 | | /// |
85 | | /// ``` |
86 | | /// use intrusive_collections::container_of; |
87 | | /// |
88 | | /// struct S { x: u32, y: u32 }; |
89 | | /// let container = S { x: 1, y: 2 }; |
90 | | /// let field = &container.x; |
91 | | /// let container2: *const S = unsafe { container_of!(field, S, x) }; |
92 | | /// assert_eq!(&container as *const S, container2); |
93 | | /// ``` |
94 | | /// |
95 | | /// # Safety |
96 | | /// |
97 | | /// This is unsafe because it assumes that the given expression is a valid |
98 | | /// pointer to the specified field of some container type. |
99 | | #[macro_export] |
100 | | macro_rules! container_of { |
101 | | ($ptr:expr, $container:path, $field:ident) => { |
102 | | #[allow(clippy::cast_ptr_alignment)] |
103 | | { |
104 | | ($ptr as *const _ as *const u8).sub($crate::offset_of!($container, $field)) |
105 | | as *const $container |
106 | | } |
107 | | }; |
108 | | } |
109 | | |
110 | | /// Macro to generate an implementation of `Adapter` for a given set of types. |
111 | | /// In particular this will automatically generate implementations of the |
112 | | /// `get_value` and `get_link` methods for a given named field in a struct. |
113 | | /// |
114 | | /// The basic syntax to create an adapter is: |
115 | | /// |
116 | | /// ```rust,ignore |
117 | | /// intrusive_adapter!(Adapter = Pointer: Value { link_field: LinkType }); |
118 | | /// ``` |
119 | | /// |
120 | | /// You can create a new instance of an adapter using the `new` method or the |
121 | | /// `NEW` associated constant. The adapter also implements the `Default` trait. |
122 | | /// |
123 | | /// # Generics |
124 | | /// |
125 | | /// This macro supports generic arguments: |
126 | | /// |
127 | | /// ```rust,ignore |
128 | | /// intrusive_adapter!( |
129 | | /// Adapter<'lifetime, Type, Type2> = |
130 | | /// Pointer: Value { |
131 | | /// link_field: LinkType |
132 | | /// } |
133 | | /// where |
134 | | /// Type: Copy, |
135 | | /// Type2: ?Sized + 'lifetime |
136 | | /// ); |
137 | | /// ``` |
138 | | /// |
139 | | /// Note that due to macro parsing limitations, `T: Trait` bounds are not |
140 | | /// supported in the generic argument list. You must list any trait bounds in |
141 | | /// a separate `where` clause at the end of the macro. |
142 | | /// |
143 | | /// # Examples |
144 | | /// |
145 | | /// ``` |
146 | | /// use intrusive_collections::{LinkedListLink, RBTreeLink}; |
147 | | /// use intrusive_collections::intrusive_adapter; |
148 | | /// |
149 | | /// pub struct Test { |
150 | | /// link: LinkedListLink, |
151 | | /// link2: RBTreeLink, |
152 | | /// } |
153 | | /// intrusive_adapter!(MyAdapter = Box<Test>: Test { link: LinkedListLink }); |
154 | | /// intrusive_adapter!(pub MyAdapter2 = Box<Test>: Test { link2: RBTreeLink }); |
155 | | /// intrusive_adapter!(pub(crate) MyAdapter3 = Box<Test>: Test { link2: RBTreeLink }); |
156 | | /// |
157 | | /// pub struct Test2<T> |
158 | | /// where T: Clone + ?Sized |
159 | | /// { |
160 | | /// link: LinkedListLink, |
161 | | /// val: T, |
162 | | /// } |
163 | | /// intrusive_adapter!(MyAdapter4<'a, T> = &'a Test2<T>: Test2<T> { link: LinkedListLink } where T: ?Sized + Clone + 'a); |
164 | | /// ``` |
165 | | #[macro_export] |
166 | | macro_rules! intrusive_adapter { |
167 | | (@impl |
168 | | $(#[$attr:meta])* $vis:vis $name:ident ($($args:tt),*) |
169 | | = $pointer:ty: $value:path { $field:ident: $link:ty } $($where_:tt)* |
170 | | ) => { |
171 | | #[allow(explicit_outlives_requirements)] |
172 | | $(#[$attr])* |
173 | | $vis struct $name<$($args),*> $($where_)* { |
174 | | link_ops: <$link as $crate::DefaultLinkOps>::Ops, |
175 | | pointer_ops: $crate::DefaultPointerOps<$pointer>, |
176 | | } |
177 | | unsafe impl<$($args),*> Send for $name<$($args),*> $($where_)* {} |
178 | | unsafe impl<$($args),*> Sync for $name<$($args),*> $($where_)* {} |
179 | | impl<$($args),*> Copy for $name<$($args),*> $($where_)* {} |
180 | | impl<$($args),*> Clone for $name<$($args),*> $($where_)* { |
181 | | #[inline] |
182 | 0 | fn clone(&self) -> Self { |
183 | 0 | *self |
184 | 0 | } |
185 | | } |
186 | | impl<$($args),*> Default for $name<$($args),*> $($where_)* { |
187 | | #[inline] |
188 | | fn default() -> Self { |
189 | | Self::NEW |
190 | | } |
191 | | } |
192 | | #[allow(dead_code)] |
193 | | impl<$($args),*> $name<$($args),*> $($where_)* { |
194 | | pub const NEW: Self = $name { |
195 | | link_ops: <$link as $crate::DefaultLinkOps>::NEW, |
196 | | pointer_ops: $crate::DefaultPointerOps::<$pointer>::new(), |
197 | | }; |
198 | | #[inline] |
199 | 992 | pub fn new() -> Self { |
200 | 992 | Self::NEW |
201 | 992 | } |
202 | | } |
203 | | #[allow(dead_code, unsafe_code)] |
204 | | unsafe impl<$($args),*> $crate::Adapter for $name<$($args),*> $($where_)* { |
205 | | type LinkOps = <$link as $crate::DefaultLinkOps>::Ops; |
206 | | type PointerOps = $crate::DefaultPointerOps<$pointer>; |
207 | | |
208 | | #[inline] |
209 | 0 | unsafe fn get_value(&self, link: <Self::LinkOps as $crate::LinkOps>::LinkPtr) -> *const <Self::PointerOps as $crate::PointerOps>::Value { |
210 | 0 | $crate::container_of!(link.as_ptr(), $value, $field) |
211 | 0 | } |
212 | | #[inline] |
213 | 0 | unsafe fn get_link(&self, value: *const <Self::PointerOps as $crate::PointerOps>::Value) -> <Self::LinkOps as $crate::LinkOps>::LinkPtr { |
214 | | // We need to do this instead of just accessing the field directly |
215 | | // to strictly follow the stack borrow rules. |
216 | 0 | let ptr = (value as *const u8).add($crate::offset_of!($value, $field)); |
217 | 0 | core::ptr::NonNull::new_unchecked(ptr as *mut _) |
218 | 0 | } |
219 | | #[inline] |
220 | 0 | fn link_ops(&self) -> &Self::LinkOps { |
221 | 0 | &self.link_ops |
222 | 0 | } |
223 | | #[inline] |
224 | 0 | fn link_ops_mut(&mut self) -> &mut Self::LinkOps { |
225 | 0 | &mut self.link_ops |
226 | 0 | } Unexecuted instantiation: <cros_async::sync::waiter::WaiterAdapter as intrusive_collections::adapter::Adapter>::link_ops_mut Unexecuted instantiation: <cros_async::sync::waiter::WaiterAdapter as intrusive_collections::adapter::Adapter>::link_ops_mut |
227 | | #[inline] |
228 | 0 | fn pointer_ops(&self) -> &Self::PointerOps { |
229 | 0 | &self.pointer_ops |
230 | 0 | } |
231 | | } |
232 | | }; |
233 | | (@find_generic |
234 | | $(#[$attr:meta])* $vis:vis $name:ident ($($prev:tt)*) > $($rest:tt)* |
235 | | ) => { |
236 | | intrusive_adapter!(@impl |
237 | | $(#[$attr])* $vis $name ($($prev)*) $($rest)* |
238 | | ); |
239 | | }; |
240 | | (@find_generic |
241 | | $(#[$attr:meta])* $vis:vis $name:ident ($($prev:tt)*) $cur:tt $($rest:tt)* |
242 | | ) => { |
243 | | intrusive_adapter!(@find_generic |
244 | | $(#[$attr])* $vis $name ($($prev)* $cur) $($rest)* |
245 | | ); |
246 | | }; |
247 | | (@find_if_generic |
248 | | $(#[$attr:meta])* $vis:vis $name:ident < $($rest:tt)* |
249 | | ) => { |
250 | | intrusive_adapter!(@find_generic |
251 | | $(#[$attr])* $vis $name () $($rest)* |
252 | | ); |
253 | | }; |
254 | | (@find_if_generic |
255 | | $(#[$attr:meta])* $vis:vis $name:ident $($rest:tt)* |
256 | | ) => { |
257 | | intrusive_adapter!(@impl |
258 | | $(#[$attr])* $vis $name () $($rest)* |
259 | | ); |
260 | | }; |
261 | | ($(#[$attr:meta])* $vis:vis $name:ident $($rest:tt)*) => { |
262 | | intrusive_adapter!(@find_if_generic |
263 | | $(#[$attr])* $vis $name $($rest)* |
264 | | ); |
265 | | }; |
266 | | } |
267 | | |
268 | | #[cfg(test)] |
269 | | mod tests { |
270 | | use crate::LinkedListLink; |
271 | | use std::rc::Rc; |
272 | | |
273 | | struct Obj { |
274 | | link: LinkedListLink, |
275 | | } |
276 | | |
277 | | intrusive_adapter! { |
278 | | /// Test doc comment |
279 | | ObjAdapter1 = Rc<Obj>: Obj { link: LinkedListLink } |
280 | | } |
281 | | } |