name-index 0.1.0

Library for accessing struct fields by name at runtime
Documentation
//! **Dynamic struct field indexing library**
//!
//! name-index implements functionality to allow users to dynamically access
//! the fields of realitively-homogenous structs by name at runtime.
//!
//! This functionality may prove useful for problems where fixed key-value
//! pairs are mapped as fields of a struct (for example to aid performance and
//! allow compile-time type checking) but which need to be accessed sparingly
//! at runtime by their respective name.
//!
//! The lookup functionality is not optimized for performance. In cases where
//! this lookup is frequently used, it is likely better to use alternatives
//! like [std::collections::HashMap].
//!
//! ## Example
//! ```rust
//! use name_index::NameIndex;
//!
//! #[derive(Default, NameIndex)]
//! struct MyStruct {
//!     // The #[index] attributes tells the derive macro to
//!     // start indexing all u32 fields from here on
//!     #[index]
//!     first: u32,
//!     second: u32,
//!     third: u32,
//! }
//!
//! fn main() {
//!     let mut my_struct = MyStruct::default();
//!
//!     // The name of the field we want to index
//!     // Might come from user input for example
//!     let name = "second";
//!
//!     // Use NameIndex::get_ref_mut to get a mutable
//!     // reference to our field
//!     let field_ref: &mut u32 =
//!         NameIndex::get_ref_mut(&mut my_struct, name)
//!         .expect("second is a field of MyStruct");
//!
//!     *field_ref = 5;
//!
//!     assert_eq!(my_struct.second, 5);
//! }
//! ```
//!
//! For the previous example the [NameIndex] derive creates the following
//! (simplified[^simpl]) code:
//!
//! ```rust
//! # use name_index::{NameIndex, Field, FieldMut};
//! # struct MyStruct {
//! #     first: u32,
//! #     second: u32,
//! #     third: u32,
//! # }
//! impl NameIndex<u32> for MyStruct {
//!     fn get_ref_mut(&mut self, name: &str) -> Option<&mut u32> {
//!         match name {
//!             "first" => Some(&mut self.first),
//!             "second" => Some(&mut self.second),
//!             "third" => Some(&mut self.third),
//!             _ => None,
//!         }
//!     }
//!     // -- snip --
//!     # fn get_ref(&self, name: &str) -> Option<&u32> {unimplemented!()}
//!     # fn fields(&self) -> Vec<Field<u32>> {unimplemented!()}
//!     # fn fields_mut(&mut self) -> Vec<FieldMut<u32>> {unimplemented!()}
//! }
//! ```
//!
//! ## Second Example
//! This example is supposed to illustrate how [NameIndexCopy] can be used
//! to save some redundant typing when the generic type of [NameIndex]
//! implements [std::marker::Copy].
//!
//! ```rust
//! use name_index::{NameIndex, NameIndexCopy};
//!
//! #[derive(Default, NameIndex)]
//! struct MyStruct {
//!     // This attributes tells the derive macro to start
//!     // indexing all u32 fields from here on
//!     #[index]
//!     first: u32,
//!     second: u32,
//!     third: u32,
//! }
//!
//! fn main() {
//!     let mut my_struct = MyStruct::default();
//!     my_struct.second = 4;
//!
//!     // We can use NameIndexCopy<u32> here because NameIndexCopy<T>
//!     // is automatically implemented for NameIndex<T> when T: Copy
//!
//!     // Get the value of my_struct.second
//!     let val: u32 = NameIndexCopy::get(&my_struct, "second")
//!         .expect("second is a field of MyStruct");
//!
//!     assert_eq!(val, my_struct.second);
//!
//!     // Set the value of my_struct.third to 7
//!     NameIndexCopy::set(&mut my_struct, "third", 7)
//!         .expect("third is a field of MyStruct");
//!
//!     assert_eq!(my_struct.third, 7);
//! }
//! ```
//!
//! [^simpl]: Only the [NameIndex::get_ref_mut] function is implemented here
//! for clarity.

/// Macro to automatically derive NameIndex
///
/// This derive can only be used for regular structs (i.e. not on tuple
/// or unit structs).
///
/// The `#[index]` attribute has to be placed on exactly one of the fields.
/// All fields with the same type, starting at that field, will be indexed
/// by the macro and can then be found through [NameIndex].
///
/// ## Example
/// ```rust
/// use name_index::NameIndex;
///
/// #[derive(Default, NameIndex)]
/// struct SomeStruct {
///     one: u16, // not indexed
///     random: String, // not indexed
///     #[index]
///     two: u16, // FOUND
///     three: u16, // FOUND
///     other: Vec<u8>, // not indexed
///     four: u16, // FOUND
/// }
///
/// // SomeStruct now implements NameIndex<u16>
///
/// let s: SomeStruct = SomeStruct::default();
/// assert_eq!(s.get_ref("one"), None);
/// assert_eq!(s.get_ref("other"), None);
///
/// let two_ref: &u16 = &s.two;
/// let found_ref: Option<&u16> = s.get_ref("two");
/// assert!(found_ref.is_some());
/// assert!(std::ptr::eq(found_ref.unwrap(), two_ref));
/// ```
pub use name_index_derive::NameIndex;

/// Named reference to a struct field
///
/// The first entry of the tuple represents the name of the field and the
/// second holds a reference to the field.
///
/// Returned by [NameIndex::fields].
pub type Field<'a, T> = (&'static str, &'a T);

/// Named mutable reference to a struct field
///
/// The first entry of the tuple represents the name of the field and the
/// second holds a mutable reference to the field.
///
/// Returned by [NameIndex::fields_mut].
pub type FieldMut<'a, T> = (&'static str, &'a mut T);

/// Struct field access trait
pub trait NameIndex<T> {
    /// Get a reference to a field by name
    ///
    /// When the field does not exist, the return value will be None.
    /// Otherwise it will be a reference to the field of the struct.
    fn get_ref(&self, name: &str) -> Option<&T>;

    /// Get a mutable reference to a field by name
    ///
    /// When the field does not exist, the return value will be None.
    /// Otherwise it will be a mutable reference to the field of the struct.
    fn get_ref_mut(&mut self, name: &str) -> Option<&mut T>;

    /// Get named references all indexed fields
    ///
    /// The returned vector contains the names and references for all of the
    /// indexed fields in tuple pairs. See [Field].
    fn fields(&self) -> Vec<Field<T>>;

    /// Get named mutable references all indexed fields
    ///
    /// The returned vector contains the names and mutable references for all
    /// of the indexed fields in tuple pairs. See [FieldMut].
    fn fields_mut(&mut self) -> Vec<FieldMut<T>>;
}

/// Struct primitive field access trait
pub trait NameIndexCopy<T: Copy>: NameIndex<T> {
    /// Get the value of a field
    ///
    /// Will be None when the field does not exist, otherwise it will be the
    /// current value.
    fn get(&self, name: &str) -> Option<T>;

    /// Set the value of a field
    ///
    /// The returned Result will be an Err when the field does not exist.
    fn set(&mut self, name: &str, value: T) -> Result<(), ()>;
}

impl<T, U: NameIndex<T>> NameIndexCopy<T> for U
where
    T: Copy,
{
    fn get(&self, name: &str) -> Option<T> {
        self.get_ref(name).map(|r| *r)
    }

    fn set(&mut self, name: &str, value: T) -> Result<(), ()> {
        self.get_ref_mut(name).ok_or(()).map(|r| *r = value)
    }
}