blob: 4f436522a243d8449ff1974fa87bcbae7ce4a0fa [file] [log] [blame]
use core::iter::{self, FusedIterator};
use crate::field::*;
use crate::*;
/// Set of values from a `Structable` or `Enumerable` with named fields.
#[derive(Debug)]
pub struct NamedValues<'a> {
fields: &'a [NamedField<'a>],
values: &'a [Value<'a>],
}
impl<'a> NamedValues<'a> {
/// Create a new `NamedValues` instance.
///
/// Both `fields` and `values` must be the same length.
///
/// # Panics
///
/// The method panics if `fields` and `values` are different lengths.
///
/// # Examples
///
/// ```
/// use valuable::{NamedField, NamedValues, Value};
///
/// let fields = [
/// NamedField::new("foo"),
/// NamedField::new("bar")
/// ];
/// let values = [
/// Value::U32(123),
/// Value::U32(456),
/// ];
///
/// let named_values = NamedValues::new(&fields, &values);
///
/// assert_eq!(
/// named_values.get(&fields[0]).unwrap().as_u32(),
/// Some(123));
/// ```
pub fn new(fields: &'a [NamedField<'a>], values: &'a [Value<'a>]) -> NamedValues<'a> {
assert!(
fields.len() == values.len(),
"`fields` and `values` must be the same length"
);
NamedValues { fields, values }
}
/// Get a value using a `NamedField` reference.
///
/// # Examples
///
/// ```
/// use valuable::{NamedField, NamedValues, Value};
///
/// let fields = [
/// NamedField::new("foo"),
/// NamedField::new("bar")
/// ];
/// let values = [
/// Value::U32(123),
/// Value::U32(456),
/// ];
///
/// let named_values = NamedValues::new(&fields, &values);
///
/// assert_eq!(
/// named_values.get(&fields[0]).unwrap().as_u32(),
/// Some(123));
/// ```
pub fn get(&self, field: &NamedField<'_>) -> Option<&Value<'_>> {
use core::mem;
let idx = (field as *const _ as usize - &self.fields[0] as *const _ as usize)
/ mem::size_of::<NamedField<'_>>();
self.values.get(idx)
}
/// Get a value using string.
///
/// # Examples
///
/// ```
/// use valuable::{NamedField, NamedValues, Value};
///
/// let fields = [
/// NamedField::new("foo"),
/// NamedField::new("bar")
/// ];
/// let values = [
/// Value::U32(123),
/// Value::U32(456),
/// ];
///
/// let named_values = NamedValues::new(&fields, &values);
///
/// assert_eq!(
/// named_values.get_by_name("foo").unwrap().as_u32(),
/// Some(123));
/// ```
pub fn get_by_name(&self, name: impl AsRef<str>) -> Option<&Value<'_>> {
let name = name.as_ref();
for (index, field) in self.fields.iter().enumerate() {
if field.name() == name {
return Some(&self.values[index]);
}
}
None
}
/// Iterate all name-value pairs.
///
/// # Examples
///
/// ```
/// use valuable::{NamedField, NamedValues, Value};
///
/// let fields = [
/// NamedField::new("foo"),
/// NamedField::new("bar")
/// ];
/// let values = [
/// Value::U32(123),
/// Value::U32(456),
/// ];
///
/// let named_values = NamedValues::new(&fields, &values);
///
/// for (field, value) in named_values.iter() {
/// println!("{:?}: {:?}", field, value);
/// }
/// ```
pub fn iter<'b>(&'b self) -> Iter<'a, 'b> {
Iter {
iter: self.fields.iter().enumerate(),
values: self.values,
}
}
/// Returns the length of fields.
pub fn len(&self) -> usize {
self.fields.len()
}
/// Returns `true` if fields have a length of 0.
pub fn is_empty(&self) -> bool {
self.fields.is_empty()
}
}
impl<'a, 'b> IntoIterator for &'b NamedValues<'a> {
type Item = (&'b NamedField<'a>, &'b Value<'a>);
type IntoIter = Iter<'a, 'b>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
/// An iterator of name-value pairs contained by [`NamedValues`].
///
/// Instances are created by the [`iter()`][NamedValues::iter] method on
/// [`NamedValues`]. See its documentation for more.
///
/// # Examples
///
/// ```
/// use valuable::{NamedField, NamedValues, Value};
///
/// let fields = [
/// NamedField::new("foo"),
/// NamedField::new("bar")
/// ];
/// let values = [
/// Value::U32(123),
/// Value::U32(456),
/// ];
///
/// let named_values = NamedValues::new(&fields, &values);
///
/// for (field, value) in named_values.iter() {
/// println!("{:?}: {:?}", field, value);
/// }
/// ```
#[derive(Debug)]
pub struct Iter<'a, 'b> {
iter: iter::Enumerate<core::slice::Iter<'b, NamedField<'a>>>,
values: &'a [Value<'a>],
}
impl<'a, 'b> Iterator for Iter<'a, 'b> {
type Item = (&'b NamedField<'a>, &'b Value<'a>);
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
.map(move |(i, field)| (field, &self.values[i]))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl DoubleEndedIterator for Iter<'_, '_> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter
.next_back()
.map(move |(i, field)| (field, &self.values[i]))
}
}
impl ExactSizeIterator for Iter<'_, '_> {
fn len(&self) -> usize {
self.iter.len()
}
}
impl FusedIterator for Iter<'_, '_> {}