name_index/lib.rs
1//! **Dynamic struct field indexing library**
2//!
3//! name-index implements functionality to allow users to dynamically access
4//! the fields of realitively-homogenous structs by name at runtime.
5//!
6//! This functionality may prove useful for problems where fixed key-value
7//! pairs are mapped as fields of a struct (for example to aid performance and
8//! allow compile-time type checking) but which need to be accessed sparingly
9//! at runtime by their respective name.
10//!
11//! The lookup functionality is not optimized for performance. In cases where
12//! this lookup is frequently used, it is likely better to use alternatives
13//! like [std::collections::HashMap].
14//!
15//! ## Example
16//! ```rust
17//! use name_index::NameIndex;
18//!
19//! #[derive(Default, NameIndex)]
20//! struct MyStruct {
21//! // The #[index] attributes tells the derive macro to
22//! // start indexing all u32 fields from here on
23//! #[index]
24//! first: u32,
25//! second: u32,
26//! third: u32,
27//! }
28//!
29//! fn main() {
30//! let mut my_struct = MyStruct::default();
31//!
32//! // The name of the field we want to index
33//! // Might come from user input for example
34//! let name = "second";
35//!
36//! // Use NameIndex::get_ref_mut to get a mutable
37//! // reference to our field
38//! let field_ref: &mut u32 =
39//! NameIndex::get_ref_mut(&mut my_struct, name)
40//! .expect("second is a field of MyStruct");
41//!
42//! *field_ref = 5;
43//!
44//! assert_eq!(my_struct.second, 5);
45//! }
46//! ```
47//!
48//! For the previous example the [NameIndex] derive creates the following
49//! (simplified[^simpl]) code:
50//!
51//! ```rust
52//! # use name_index::{NameIndex, Field, FieldMut};
53//! # struct MyStruct {
54//! # first: u32,
55//! # second: u32,
56//! # third: u32,
57//! # }
58//! impl NameIndex<u32> for MyStruct {
59//! fn get_ref_mut(&mut self, name: &str) -> Option<&mut u32> {
60//! match name {
61//! "first" => Some(&mut self.first),
62//! "second" => Some(&mut self.second),
63//! "third" => Some(&mut self.third),
64//! _ => None,
65//! }
66//! }
67//! // -- snip --
68//! # fn get_ref(&self, name: &str) -> Option<&u32> {unimplemented!()}
69//! # fn fields(&self) -> Vec<Field<u32>> {unimplemented!()}
70//! # fn fields_mut(&mut self) -> Vec<FieldMut<u32>> {unimplemented!()}
71//! # fn field_aliases(&self, name: &str) -> Vec<&'static str>
72//! # {unimplemented!()}
73//! # fn resolve_alias(&self, name: &str) -> Option<&'static str>
74//! # {unimplemented!()}
75//! }
76//! ```
77//!
78//! ## Second Example
79//! This example is supposed to illustrate how [NameIndexCopy] can be used
80//! to save some redundant typing when the generic type of [NameIndex]
81//! implements [std::marker::Copy].
82//!
83//! ```rust
84//! use name_index::{NameIndex, NameIndexCopy};
85//!
86//! #[derive(NameIndex)]
87//! struct MyStruct {
88//! // When no `#[index]` attribute is given, the first field is
89//! // automatically chosen as the reference.
90//! first: u32,
91//! second: u32,
92//! third: u32,
93//! }
94//!
95//! fn main() {
96//! let mut my_struct = MyStruct {
97//! first: 1,
98//! second: 2,
99//! third: 3,
100//! };
101//!
102//! // We can use NameIndexCopy<u32> here because NameIndexCopy<T>
103//! // is automatically implemented for NameIndex<T> when T: Copy
104//!
105//! // Get the value of my_struct.third
106//! let val: u32 = NameIndexCopy::get(&my_struct, "third")
107//! .expect("'third' is a field of MyStruct");
108//!
109//! assert_eq!(val, my_struct.third);
110//!
111//! // Set the value of my_struct.first to 7
112//! NameIndexCopy::set(&mut my_struct, "first", 7)
113//! .expect("'first' is a field of MyStruct");
114//!
115//! assert_eq!(my_struct.first, 7);
116//! }
117//! ```
118//!
119//! [^simpl]: Only the [NameIndex::get_ref_mut] function is implemented here
120//! for clarity.
121
122/// Macro to automatically derive NameIndex
123///
124/// This derive can only be used for regular structs (i.e. not on tuple
125/// or unit structs).
126///
127/// The `#[index]` attribute can only be placed on one of the fields.
128/// If it isn't present, the first field is chosen as if it had the attribute.
129/// All fields with the same type, starting at that field, will be indexed
130/// by the macro and can then be found through [NameIndex].
131///
132/// The `#[alias(...)]` attribute can be used to define aliases for the field.
133/// Aliases behave exactly like the actual name of the field when using
134/// [NameIndex::get_ref] and [NameIndex::get_ref_mut].
135///
136/// ## Example
137/// ```rust
138/// use name_index::NameIndex;
139///
140/// #[derive(Default, NameIndex)]
141/// struct SomeStruct {
142/// one: u16, // not indexed
143/// random: String, // not indexed
144/// #[index]
145/// two: u16, // FOUND
146/// three: u16, // FOUND
147/// other: Vec<u8>, // not indexed
148/// #[alias(f)]
149/// four: u16, // FOUND
150/// }
151///
152/// // SomeStruct now implements NameIndex<u16>
153///
154/// let s: SomeStruct = SomeStruct::default();
155/// assert_eq!(s.get_ref("one"), None);
156/// assert_eq!(s.get_ref("other"), None);
157///
158/// let two_ref: &u16 = &s.two;
159/// let found_ref: Option<&u16> = s.get_ref("two");
160/// assert!(found_ref.is_some());
161/// assert!(std::ptr::eq(found_ref.unwrap(), two_ref));
162///
163/// // The "four" field of SomeStruct has the alias "f" and get_ref treats them
164/// // the exact same way.
165/// let four_ref: &u16 = s.get_ref("four").unwrap();
166/// let f_ref: &u16 = s.get_ref("f").unwrap();
167/// assert!(std::ptr::eq(four_ref, f_ref));
168/// ```
169pub use name_index_derive::NameIndex;
170
171/// Named reference to a struct field
172///
173/// The first entry of the tuple represents the name of the field and the
174/// second holds a reference to the field.
175///
176/// Returned by [NameIndex::fields].
177pub type Field<'a, T> = (&'static str, &'a T);
178
179/// Named mutable reference to a struct field
180///
181/// The first entry of the tuple represents the name of the field and the
182/// second holds a mutable reference to the field.
183///
184/// Returned by [NameIndex::fields_mut].
185pub type FieldMut<'a, T> = (&'static str, &'a mut T);
186
187/// Struct field access trait
188///
189/// Designed to be derived through [NameIndex][name_index_derive::NameIndex].
190pub trait NameIndex<T> {
191 /// Get a reference to a field by name
192 ///
193 /// When the field does not exist, the return value will be None.
194 /// Otherwise it will be a reference to the field of the struct.
195 ///
196 /// The name may be an alias of the field instead of the true name.
197 /// See `#[alias(...)]` in the [derive macro][name_index_derive::NameIndex].
198 fn get_ref(&self, name: &str) -> Option<&T>;
199
200 /// Get a mutable reference to a field by name
201 ///
202 /// When the field does not exist, the return value will be None.
203 /// Otherwise it will be a mutable reference to the field of the struct.
204 ///
205 /// The name may be an alias of the field instead of the true name.
206 /// See `#[alias(...)]` in the [derive macro][name_index_derive::NameIndex].
207 fn get_ref_mut(&mut self, name: &str) -> Option<&mut T>;
208
209 /// Get named references all indexed fields
210 ///
211 /// The returned vector contains the names and references for all of the
212 /// indexed fields in tuple pairs. See [Field].
213 fn fields(&self) -> Vec<Field<T>>;
214
215 /// Get named mutable references all indexed fields
216 ///
217 /// The returned vector contains the names and mutable references for all
218 /// of the indexed fields in tuple pairs. See [FieldMut].
219 fn fields_mut(&mut self) -> Vec<FieldMut<T>>;
220
221 /// Get all aliases of a field
222 ///
223 /// If the field doesn't exist, an empty vector will be returned.
224 ///
225 /// The name parameter has to be the true name of the field.
226 /// See [resolve_alias][NameIndex::resolve_alias] for finding the true name
227 /// from an alias.
228 fn field_aliases(&self, name: &str) -> Vec<&'static str>;
229
230 /// Get true name of a field
231 ///
232 /// The name parameter can be anything that can be passed to
233 /// [get_ref][NameIndex::get_ref]. Aliases will be resolved to the actual
234 /// name of the field and when given the true name, it is just resolved to
235 /// itself.
236 ///
237 /// If the name doesn't match any field names or aliases of the struct,
238 /// a None value will be returned.
239 fn resolve_alias(&self, name: &str) -> Option<&'static str>;
240}
241
242/// Struct primitive field access trait
243pub trait NameIndexCopy<T: Copy>: NameIndex<T> {
244 /// Get the value of a field
245 ///
246 /// Will be None when the field does not exist, otherwise it will be the
247 /// current value.
248 fn get(&self, name: &str) -> Option<T>;
249
250 /// Set the value of a field
251 ///
252 /// The returned Result will be an Err when the field does not exist.
253 fn set(&mut self, name: &str, value: T) -> Result<(), ()>;
254}
255
256impl<T, U: NameIndex<T>> NameIndexCopy<T> for U
257where
258 T: Copy,
259{
260 fn get(&self, name: &str) -> Option<T> {
261 self.get_ref(name).map(|r| *r)
262 }
263
264 fn set(&mut self, name: &str, value: T) -> Result<(), ()> {
265 self.get_ref_mut(name).ok_or(()).map(|r| *r = value)
266 }
267}