• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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`.
get_value( &self, link: <Self::LinkOps as LinkOps>::LinkPtr, ) -> *const <Self::PointerOps as PointerOps>::Value55     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.
get_link( &self, value: *const <Self::PointerOps as PointerOps>::Value, ) -> <Self::LinkOps as LinkOps>::LinkPtr65     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.
link_ops(&self) -> &Self::LinkOps71     fn link_ops(&self) -> &Self::LinkOps;
72 
73     /// Returns a reference to the mutable link operations.
link_ops_mut(&mut self) -> &mut Self::LinkOps74     fn link_ops_mut(&mut self) -> &mut Self::LinkOps;
75 
76     /// Returns a reference to the pointer converter.
pointer_ops(&self) -> &Self::PointerOps77     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 ///
156 /// pub struct Test2<T>
157 ///     where T: Clone + ?Sized
158 /// {
159 ///     link: LinkedListLink,
160 ///     val: T,
161 /// }
162 /// intrusive_adapter!(MyAdapter3<'a, T> = &'a Test2<T>: Test2<T> { link: LinkedListLink } where T: ?Sized + Clone + 'a);
163 /// ```
164 #[macro_export]
165 macro_rules! intrusive_adapter {
166     (@impl
167         $(#[$attr:meta])* ($($privacy:tt)*) $name:ident ($($args:tt),*)
168         = $pointer:ty: $value:path { $field:ident: $link:ty } $($where_:tt)*
169     ) => {
170         #[allow(explicit_outlives_requirements)]
171         $(#[$attr])*
172         $($privacy)* struct $name<$($args),*> $($where_)* {
173             link_ops: <$link as $crate::DefaultLinkOps>::Ops,
174             pointer_ops: $crate::DefaultPointerOps<$pointer>,
175         }
176         unsafe impl<$($args),*> Send for $name<$($args),*> $($where_)* {}
177         unsafe impl<$($args),*> Sync for $name<$($args),*> $($where_)* {}
178         impl<$($args),*> Copy for $name<$($args),*> $($where_)* {}
179         impl<$($args),*> Clone for $name<$($args),*> $($where_)* {
180             #[inline]
181             fn clone(&self) -> Self {
182                 *self
183             }
184         }
185         impl<$($args),*> Default for $name<$($args),*> $($where_)* {
186             #[inline]
187             fn default() -> Self {
188                 Self::NEW
189             }
190         }
191         #[allow(dead_code)]
192         impl<$($args),*> $name<$($args),*> $($where_)* {
193             pub const NEW: Self = $name {
194                 link_ops: <$link as $crate::DefaultLinkOps>::NEW,
195                 pointer_ops: $crate::DefaultPointerOps::<$pointer>::new(),
196             };
197             #[inline]
198             pub fn new() -> Self {
199                 Self::NEW
200             }
201         }
202         #[allow(dead_code, unsafe_code)]
203         unsafe impl<$($args),*> $crate::Adapter for $name<$($args),*> $($where_)* {
204             type LinkOps = <$link as $crate::DefaultLinkOps>::Ops;
205             type PointerOps = $crate::DefaultPointerOps<$pointer>;
206 
207             #[inline]
208             unsafe fn get_value(&self, link: <Self::LinkOps as $crate::LinkOps>::LinkPtr) -> *const <Self::PointerOps as $crate::PointerOps>::Value {
209                 $crate::container_of!(link.as_ptr(), $value, $field)
210             }
211             #[inline]
212             unsafe fn get_link(&self, value: *const <Self::PointerOps as $crate::PointerOps>::Value) -> <Self::LinkOps as $crate::LinkOps>::LinkPtr {
213                 // We need to do this instead of just accessing the field directly
214                 // to strictly follow the stack borrow rules.
215                 let ptr = (value as *const u8).add($crate::offset_of!($value, $field));
216                 core::ptr::NonNull::new_unchecked(ptr as *mut _)
217             }
218             #[inline]
219             fn link_ops(&self) -> &Self::LinkOps {
220                 &self.link_ops
221             }
222             #[inline]
223             fn link_ops_mut(&mut self) -> &mut Self::LinkOps {
224                 &mut self.link_ops
225             }
226             #[inline]
227             fn pointer_ops(&self) -> &Self::PointerOps {
228                 &self.pointer_ops
229             }
230         }
231     };
232     (@find_generic
233         $(#[$attr:meta])* ($($privacy:tt)*) $name:ident ($($prev:tt)*) > $($rest:tt)*
234     ) => {
235         intrusive_adapter!(@impl
236             $(#[$attr])* ($($privacy)*) $name ($($prev)*) $($rest)*
237         );
238     };
239     (@find_generic
240         $(#[$attr:meta])* ($($privacy:tt)*) $name:ident ($($prev:tt)*) $cur:tt $($rest:tt)*
241     ) => {
242         intrusive_adapter!(@find_generic
243             $(#[$attr])* ($($privacy)*) $name ($($prev)* $cur) $($rest)*
244         );
245     };
246     (@find_if_generic
247         $(#[$attr:meta])* ($($privacy:tt)*) $name:ident < $($rest:tt)*
248     ) => {
249         intrusive_adapter!(@find_generic
250             $(#[$attr])* ($($privacy)*) $name () $($rest)*
251         );
252     };
253     (@find_if_generic
254         $(#[$attr:meta])* ($($privacy:tt)*) $name:ident $($rest:tt)*
255     ) => {
256         intrusive_adapter!(@impl
257             $(#[$attr])* ($($privacy)*) $name () $($rest)*
258         );
259     };
260     ($(#[$attr:meta])* pub $name:ident $($rest:tt)*) => {
261         intrusive_adapter!(@find_if_generic
262             $(#[$attr])* (pub) $name $($rest)*
263         );
264     };
265     ($(#[$attr:meta])* $name:ident $($rest:tt)*) => {
266         intrusive_adapter!(@find_if_generic
267             $(#[$attr])* () $name $($rest)*
268         );
269     };
270 }
271 
272 #[cfg(test)]
273 mod tests {
274     use crate::LinkedListLink;
275     use std::rc::Rc;
276 
277     struct Obj {
278         link: LinkedListLink,
279     }
280 
281     #[deny(missing_docs)]
282     intrusive_adapter! {
283         /// Test doc comment
284         ObjAdapter1 = Rc<Obj>: Obj { link: LinkedListLink }
285     }
286 }
287