zone_alloc_strong_handle_derive/lib.rs
1//! Procedural macro for deriving the [`zone_alloc::StrongHandle`] interface on simple wrappers
2//! around [`zone_alloc::Handle`].
3//!
4//! # Example
5//! ```
6//! use zone_alloc::{
7//! Handle,
8//! StrongRegistry,
9//! };
10//! use zone_alloc_strong_handle_derive::StrongHandle;
11//!
12//! #[derive(Clone, Copy, Debug, PartialEq, Eq, StrongHandle)]
13//! struct NodeHandle(Handle);
14//!
15//! #[derive(Debug, PartialEq, Eq)]
16//! struct Node<T> {
17//! parent: Option<NodeHandle>,
18//! value: T,
19//! }
20//!
21//! impl<T> Node<T> {
22//! pub fn new(parent: Option<NodeHandle>, value: T) -> Self {
23//! Self { parent, value }
24//! }
25//! }
26//!
27//! fn main() {
28//! let registry = StrongRegistry::<NodeHandle, Node<&str>>::new();
29//! let root_handle = registry.register(Node::new(None, "first"));
30//! let handle = registry.register(Node::new(Some(root_handle), "second"));
31//! let handle = registry.register(Node::new(Some(handle), "third"));
32//! registry.get_mut(root_handle).unwrap().parent = Some(handle);
33//!
34//! let node = registry.get(handle).unwrap();
35//! assert_eq!(node.value, "third");
36//! let node = registry.get(node.parent.unwrap()).unwrap();
37//! assert_eq!(node.value, "second");
38//! let node = registry.get(node.parent.unwrap()).unwrap();
39//! assert_eq!(node.value, "first");
40//! let node = registry.get(node.parent.unwrap()).unwrap();
41//! assert_eq!(node.value, "third");
42//! }
43//! ```
44
45#![no_std]
46
47extern crate proc_macro;
48
49mod parse;
50
51use parse::Input;
52use proc_macro::TokenStream;
53use proc_macro2::{
54 Ident,
55 Span,
56};
57use proc_macro_crate::{
58 crate_name,
59 FoundCrate,
60};
61use quote::quote;
62use syn::parse_macro_input;
63
64#[proc_macro_derive(StrongHandle)]
65pub fn derive_strong_handle(input: TokenStream) -> TokenStream {
66 let input = parse_macro_input!(input as Input);
67 let ident = input.ident;
68
69 let call_site = Span::call_site();
70 let found_crate = crate_name("zone-alloc").expect("zone-alloc is present in `Cargo.toml`");
71 let crate_token = match found_crate {
72 FoundCrate::Itself => quote!(crate),
73 FoundCrate::Name(name) => {
74 let ident = Ident::new(&name, call_site);
75 quote!(#ident)
76 }
77 };
78 let handle_type = quote! {
79 #crate_token::Handle
80 };
81 let strong_handle = quote! {
82 #crate_token::StrongHandle
83 };
84
85 TokenStream::from(quote! {
86 impl core::convert::From<#handle_type> for #ident {
87 fn from(value: #handle_type) -> Self {
88 Self(value.into())
89 }
90 }
91 impl #strong_handle for #ident {
92 fn handle(&self) -> #handle_type {
93 self.0
94 }
95 }
96 })
97}