use core::fmt;
use crate::hlist::{Coniunctio, HList, Nihil};
use crate::labelled::Field;
use super::campus::{Confluo, Extendo, HabetCampum, Muto, Restricto};
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Registrum<R> {
pub(crate) fields: R,
}
impl Registrum<Nihil> {
#[inline]
pub fn new() -> Self {
Registrum { fields: Nihil }
}
}
impl Default for Registrum<Nihil> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<R: HList> Registrum<R> {
#[inline]
pub fn from_hlist(fields: R) -> Self {
Registrum { fields }
}
#[inline]
pub fn into_hlist(self) -> R {
self.fields
}
#[inline]
pub fn as_hlist(&self) -> &R {
&self.fields
}
#[inline]
pub fn len(&self) -> usize {
self.fields.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.fields.is_empty()
}
}
impl<R> Registrum<R> {
#[inline]
pub fn extend_field<Label, Value>(
self,
name: &'static str,
value: Value,
) -> Registrum<R::Output>
where
R: Extendo<Label, Value>,
{
Registrum {
fields: self.fields.extend(name, value),
}
}
#[inline]
pub fn get<Label, Value, Index>(&self) -> &Value
where
R: HabetCampum<Label, Value, Index>,
{
self.fields.get_field()
}
#[inline]
pub fn get_mut<Label, Value, Index>(&mut self) -> &mut Value
where
R: HabetCampum<Label, Value, Index>,
{
self.fields.get_field_mut()
}
#[inline]
pub fn restrict<Label, Index>(self) -> (R::Value, Registrum<R::Remainder>)
where
R: Restricto<Label, Index>,
{
let (value, remainder) = self.fields.restrict();
(value, Registrum { fields: remainder })
}
#[inline]
pub fn merge<Other>(self, other: Registrum<Other>) -> Registrum<R::Output>
where
R: Confluo<Other>,
{
Registrum {
fields: self.fields.merge(other.fields),
}
}
#[inline]
pub fn modify<Label, NewValue, Index, F>(self, f: F) -> Registrum<R::Output>
where
R: Muto<Label, NewValue, Index>,
F: FnOnce(R::OldValue) -> NewValue,
{
Registrum {
fields: self.fields.modify(f),
}
}
}
impl fmt::Debug for Registrum<Nihil> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Registrum {{}}")
}
}
impl<Label, Value: fmt::Debug, Tail: HList> fmt::Debug
for Registrum<Coniunctio<Field<Label, Value>, Tail>>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Registrum {{ {}: {:?}, ... }}",
self.fields.head.name, self.fields.head.value
)
}
}
pub trait RegistrumExt<R> {
fn with<F, T>(self, f: F) -> T
where
F: FnOnce(Registrum<R>) -> T;
}
impl<R> RegistrumExt<R> for Registrum<R> {
#[inline]
fn with<F, T>(self, f: F) -> T
where
F: FnOnce(Registrum<R>) -> T,
{
f(self)
}
}
impl<R: HList> From<R> for Registrum<R> {
#[inline]
fn from(fields: R) -> Self {
Registrum { fields }
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::indices::Here;
use crate::labelled::chars::*;
type Name = (Ln, La, Lm, Le);
type Age = (La, Lg, Le);
#[test]
fn test_registrum_new() {
let record = Registrum::new();
assert!(record.is_empty());
assert_eq!(record.len(), 0);
}
#[test]
fn test_registrum_from_hlist() {
let hlist = hlist![field!(Name, "Alice")];
let record = Registrum::from_hlist(hlist);
assert!(!record.is_empty());
assert_eq!(record.len(), 1);
}
#[test]
fn test_registrum_into_hlist() {
let hlist = hlist![field!(Name, "Alice")];
let record = Registrum::from_hlist(hlist);
let back = record.into_hlist();
assert_eq!(back, hlist);
}
#[test]
fn test_registrum_extend() {
let record = Registrum::new()
.extend_field::<Name, _>("name", "Alice")
.extend_field::<Age, _>("age", 30i32);
assert_eq!(record.len(), 2);
}
#[test]
fn test_registrum_get() {
let record = Registrum::from_hlist(hlist![field!(Name, "Alice"), field!(Age, 30i32)]);
let name: &&str = record.get::<Name, &str, Here>();
assert_eq!(*name, "Alice");
}
#[test]
fn test_registrum_restrict() {
let record = Registrum::from_hlist(hlist![field!(Name, "Alice"), field!(Age, 30i32)]);
let (name, rest): (&str, _) = record.restrict::<Name, Here>();
assert_eq!(name, "Alice");
assert_eq!(rest.len(), 1);
}
#[test]
fn test_registrum_merge() {
let r1 = Registrum::from_hlist(hlist![field!(Name, "Alice")]);
let r2 = Registrum::from_hlist(hlist![field!(Age, 30i32)]);
let merged = r1.merge(r2);
assert_eq!(merged.len(), 2);
}
#[test]
fn test_registrum_modify() {
let record = Registrum::from_hlist(hlist![field!(Age, 30i32)]);
let modified = record.modify::<Age, i32, Here, _>(|age| age + 1);
let age: &i32 = modified.get::<Age, i32, Here>();
assert_eq!(*age, 31);
}
#[test]
fn test_registrum_debug() {
let record = Registrum::new();
let debug = alloc::format!("{record:?}");
assert!(debug.contains("Registrum"));
}
}