-
Notifications
You must be signed in to change notification settings - Fork 110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Define a macro to create self-referencing type and use it for font face #184
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/// Used for creating container type that self-reference owned data, | ||
/// see also <https://morestina.net/blog/1868/self-referential-types-for-fun-and-profit> | ||
/// | ||
/// # Example | ||
/// | ||
/// ```ignore | ||
/// struct Data(); | ||
/// struct SomeRef<'a>(&'a Data); | ||
/// | ||
/// mod inner { | ||
/// impl_self_ref!(Container, SomeRef<'static>, SomeRef<'this>); | ||
/// } | ||
/// use inner::Container; | ||
/// | ||
/// let container = Container::new(Data(), |data| SomeRef(data)); | ||
/// let some_ref = container.as_ref(); | ||
/// ``` | ||
macro_rules! impl_self_ref { | ||
($SelfRef:ident, $RefStatic:ty, $RefThis:ty) => { | ||
/// # Safety invariant | ||
/// | ||
/// `data` must never have a mutable reference taken, nor be modified during the lifetime of | ||
/// this struct | ||
pub struct $SelfRef<T> { | ||
/// `data_ref` could self-referencing `data` | ||
data_ref: $RefStatic, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This field needs to be wrapped in |
||
/// `data` field must be after `data_ref` to ensure that it is dropped later | ||
data: ::aliasable::boxed::AliasableBox<T>, | ||
} | ||
impl<T> ::core::fmt::Debug for $SelfRef<T> { | ||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { | ||
f.debug_struct(stringify!($SelfRef)).finish_non_exhaustive() | ||
} | ||
} | ||
|
||
impl<'this, T> AsRef<$RefThis> for $SelfRef<T> | ||
where | ||
Self: 'this, | ||
{ | ||
fn as_ref(&self) -> &$RefThis { | ||
&self.data_ref | ||
} | ||
} | ||
|
||
impl<T> $SelfRef<T> { | ||
pub fn new<F>(data: T, builder: F) -> Option<Self> | ||
where | ||
T: 'static, | ||
for<'this> F: FnOnce(&'this T) -> Option<$RefThis>, | ||
{ | ||
unsafe fn change_lifetime<'old, 'new: 'old, T: 'new>(data: &'old T) -> &'new T { | ||
&*(data as *const _) | ||
} | ||
let data = | ||
::aliasable::boxed::AliasableBox::from_unique(::alloc::boxed::Box::new(data)); | ||
let data_ref = builder(unsafe { change_lifetime(&data) })?; | ||
Some(Self { data_ref, data }) | ||
} | ||
|
||
/// # Safety | ||
/// | ||
/// Allows immutable access to data only | ||
#[allow(dead_code)] | ||
pub fn as_backing_data(&self) -> &T { | ||
&self.data | ||
} | ||
} | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrapping this up in a module is necessary to prevent accessing the fields incorrectly so it should probably be part of the macro