#![allow(unused)]
#![allow(clippy::missing_const_for_fn)]
#![allow(clippy::unnecessary_wraps)]
#![allow(clippy::unused_self)]
#![allow(clippy::extra_unused_type_parameters)]
#![allow(clippy::option_if_let_else)]
#[cfg(feature = "std")]
extern crate std;
use core::{any::Any, ops::Deref};
use alloc::sync::Arc;
use spin::RwLock;
use crate::{
Error, RemappingList, RemappingTarget, check_local_key, check_top_level_key,
database::Database,
entry::{EntryPtr, EntryReadGuard, EntryWriteGuard},
error::Result,
};
pub struct Databoard(Arc<DataboardInner>);
impl Clone for Databoard {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl core::fmt::Debug for Databoard {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Databoard {{ ")?;
write!(f, "autoremap: {:?}", &self.0.autoremap)?;
write!(f, ", {:?}", &*self.0.database.read())?;
write!(f, ", {:?}", &self.0.remappings)?;
write!(f, ", parent: ")?;
if let Some(parent) = &self.0.parent {
write!(f, "{parent:?}",)
} else {
write!(f, "None")
}?;
write!(f, " }}")
}
}
impl Deref for Databoard {
type Target = DataboardInner;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Default for Databoard {
fn default() -> Self {
Self(Arc::new(DataboardInner {
database: RwLock::new(Database::default()),
parent: None,
remappings: RemappingList::default(),
autoremap: false,
}))
}
}
impl Databoard {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn with(parent: Option<Self>, remappings: Option<RemappingList>, autoremap: bool) -> Self {
let remappings = remappings.unwrap_or_default();
let database = RwLock::new(Database::default());
Self(Arc::new(DataboardInner {
database,
parent,
remappings,
autoremap,
}))
}
#[must_use]
pub fn with_parent(parent: Self) -> Self {
let database = RwLock::new(Database::default());
Self(Arc::new(DataboardInner {
database,
parent: Some(parent),
remappings: RemappingList::default(),
autoremap: true,
}))
}
}
#[derive(Default)]
pub struct DataboardInner {
database: RwLock<Database>,
parent: Option<Databoard>,
remappings: RemappingList,
autoremap: bool,
}
impl DataboardInner {
#[must_use]
pub fn contains_key(&self, key: &str) -> bool {
match check_top_level_key(key) {
Ok(stripped_key) => self.root().contains_key(stripped_key),
Err(original_key) => match check_local_key(original_key) {
Ok(local_key) => self.database.read().contains_key(local_key),
Err(original_key) => match self.remappings.find(original_key) {
RemappingTarget::BoardPointer(remapped_key) => {
if let Some(parent) = &self.parent {
parent.contains_key(&remapped_key)
} else {
false
}
}
RemappingTarget::LocalPointer(remapped_key) => self.database.read().contains_key(&remapped_key),
RemappingTarget::RootPointer(remapped_key) => self.root().contains_key(&remapped_key),
RemappingTarget::StringAssignment(_) => false,
RemappingTarget::None(original_key) => {
if self.autoremap
&& let Some(parent) = &self.parent
{
parent.contains_key(&original_key)
} else {
self.database.read().contains_key(&original_key)
}
}
},
},
}
}
pub fn contains<T: Any + Send + Sync>(&self, key: &str) -> Result<bool> {
match check_top_level_key(key) {
Ok(stripped_key) => self.root().contains::<T>(stripped_key),
Err(original_key) => match check_local_key(original_key) {
Ok(local_key) => self.database.read().contains::<T>(local_key),
Err(original_key) => match self.remappings.find(original_key) {
RemappingTarget::BoardPointer(remapped_key) => self.parent.as_ref().map_or_else(
|| {
Err(Error::NoParent {
key: key.into(),
remapped: remapped_key.clone(),
})
},
|parent| parent.contains::<T>(&remapped_key),
),
RemappingTarget::LocalPointer(remapped_key) => self.database.read().contains::<T>(&remapped_key),
RemappingTarget::RootPointer(remapped_key) => self.root().contains::<T>(&remapped_key),
RemappingTarget::StringAssignment(assignment) => Err(Error::Assignment {
key: original_key.into(),
value: assignment,
}),
RemappingTarget::None(original_key) => {
if self.autoremap
&& let Some(parent) = &self.parent
{
parent.contains::<T>(&original_key)
} else {
self.database.read().contains::<T>(&original_key)
}
}
},
},
}
}
#[cfg(feature = "std")]
pub fn debug_message(&self) {
let _ = self.parent;
std::println!("not yet implemented");
}
pub fn delete<T: Any + Send + Sync>(&self, key: &str) -> Result<T> {
match check_top_level_key(key) {
Ok(stripped_key) => self.root().delete(stripped_key),
Err(original_key) => match check_local_key(original_key) {
Ok(local_key) => self.database.write().delete(local_key),
Err(original_key) => match self.remappings.find(original_key) {
RemappingTarget::BoardPointer(remapped_key) => self.parent.as_ref().map_or_else(
|| {
Err(Error::NoParent {
key: key.into(),
remapped: remapped_key.clone(),
})
},
|parent| parent.delete(&remapped_key),
),
RemappingTarget::LocalPointer(remapped_key) => self.database.write().delete(&remapped_key),
RemappingTarget::RootPointer(remapped_key) => self.root().delete(&remapped_key),
RemappingTarget::StringAssignment(assignment) => Err(Error::Assignment {
key: original_key.into(),
value: assignment,
}),
RemappingTarget::None(original_key) => {
if self.autoremap
&& let Some(parent) = &self.parent
{
parent.delete(&original_key)
} else {
self.database.write().delete(&original_key)
}
}
},
},
}
}
pub fn entry(&self, key: &str) -> Result<EntryPtr> {
match check_top_level_key(key) {
Ok(stripped_key) => self.root().entry(stripped_key),
Err(original_key) => match check_local_key(original_key) {
Ok(local_key) => self.database.read().entry(local_key),
Err(original_key) => match self.remappings.find(original_key) {
RemappingTarget::BoardPointer(remapped_key) => self.parent.as_ref().map_or_else(
|| {
Err(Error::NoParent {
key: key.into(),
remapped: remapped_key.clone(),
})
},
|parent| parent.entry(&remapped_key),
),
RemappingTarget::LocalPointer(remapped_key) => self.database.read().entry(&remapped_key),
RemappingTarget::RootPointer(remapped_key) => self.root().entry(&remapped_key),
RemappingTarget::StringAssignment(assignment) => Err(Error::Assignment {
key: original_key.into(),
value: assignment,
}),
RemappingTarget::None(original_key) => {
if self.autoremap
&& let Some(parent) = &self.parent
{
parent.entry(&original_key)
} else {
self.database.read().entry(&original_key)
}
}
},
},
}
}
pub fn get<T: Any + Clone + Send + Sync>(&self, key: &str) -> Result<T> {
match check_top_level_key(key) {
Ok(stripped_key) => self.root().get(stripped_key),
Err(original_key) => match check_local_key(original_key) {
Ok(local_key) => self.database.read().read(local_key),
Err(original_key) => match self.remappings.find(original_key) {
RemappingTarget::BoardPointer(remapped_key) => self.parent.as_ref().map_or_else(
|| {
Err(Error::NoParent {
key: key.into(),
remapped: remapped_key.clone(),
})
},
|parent| parent.get(&remapped_key),
),
RemappingTarget::LocalPointer(remapped_key) => self.database.read().read(&remapped_key),
RemappingTarget::RootPointer(remapped_key) => self.root().get(&remapped_key),
RemappingTarget::StringAssignment(assignment) => Err(Error::Assignment {
key: original_key.into(),
value: assignment,
}),
RemappingTarget::None(original_key) => {
if self.autoremap
&& let Some(parent) = &self.parent
{
parent.get(&original_key)
} else {
self.database.read().read(&original_key)
}
}
},
},
}
}
pub fn get_mut_ref<T: Any + Send + Sync>(&self, key: &str) -> Result<EntryWriteGuard<T>> {
match check_top_level_key(key) {
Ok(stripped_key) => self.root().get_mut_ref(stripped_key),
Err(original_key) => match check_local_key(original_key) {
Ok(local_key) => self.database.read().get_mut_ref(local_key),
Err(original_key) => match self.remappings.find(original_key) {
RemappingTarget::BoardPointer(remapped_key) => self.parent.as_ref().map_or_else(
|| {
Err(Error::NoParent {
key: key.into(),
remapped: remapped_key.clone(),
})
},
|parent| parent.get_mut_ref(&remapped_key),
),
RemappingTarget::LocalPointer(remapped_key) => self.database.read().get_mut_ref(&remapped_key),
RemappingTarget::RootPointer(remapped_key) => self.root().get_mut_ref(&remapped_key),
RemappingTarget::StringAssignment(assignment) => Err(Error::Assignment {
key: original_key.into(),
value: assignment,
}),
RemappingTarget::None(original_key) => {
if self.autoremap
&& let Some(parent) = &self.parent
{
parent.get_mut_ref(&original_key)
} else {
self.database.read().get_mut_ref(&original_key)
}
}
},
},
}
}
pub fn get_ref<T: Any + Send + Sync>(&self, key: &str) -> Result<EntryReadGuard<T>> {
match check_top_level_key(key) {
Ok(stripped_key) => self.root().get_ref(stripped_key),
Err(original_key) => match check_local_key(original_key) {
Ok(local_key) => self.database.read().get_ref(local_key),
Err(original_key) => match self.remappings.find(original_key) {
RemappingTarget::BoardPointer(remapped_key) => self.parent.as_ref().map_or_else(
|| {
Err(Error::NoParent {
key: key.into(),
remapped: remapped_key.clone(),
})
},
|parent| parent.get_ref(&remapped_key),
),
RemappingTarget::LocalPointer(remapped_key) => self.database.read().get_ref(&remapped_key),
RemappingTarget::RootPointer(remapped_key) => self.root().get_ref(&remapped_key),
RemappingTarget::StringAssignment(assignment) => Err(Error::Assignment {
key: original_key.into(),
value: assignment,
}),
RemappingTarget::None(original_key) => {
if self.autoremap
&& let Some(parent) = &self.parent
{
parent.get_ref(&original_key)
} else {
self.database.read().get_ref(&original_key)
}
}
},
},
}
}
pub fn remappings(&self) -> Option<&RemappingList> {
if self.remappings.is_empty() {
None
} else {
Some(&self.remappings)
}
}
fn root(&self) -> &Self {
self.parent
.as_ref()
.map_or(self, |board| board.root())
}
pub fn sequence_id(&self, key: &str) -> Result<usize> {
match check_top_level_key(key) {
Ok(stripped_key) => self.root().sequence_id(stripped_key),
Err(original_key) => match check_local_key(original_key) {
Ok(local_key) => self.database.read().sequence_id(local_key),
Err(original_key) => match self.remappings.find(original_key) {
RemappingTarget::BoardPointer(remapped_key) => self.parent.as_ref().map_or_else(
|| {
Err(Error::NoParent {
key: key.into(),
remapped: remapped_key.clone(),
})
},
|parent| parent.sequence_id(&remapped_key),
),
RemappingTarget::LocalPointer(remapped_key) => self.database.read().sequence_id(&remapped_key),
RemappingTarget::RootPointer(remapped_key) => self.root().sequence_id(&remapped_key),
RemappingTarget::StringAssignment(assignment) => Err(Error::Assignment {
key: original_key.into(),
value: assignment,
}),
RemappingTarget::None(original_key) => {
if self.autoremap
&& let Some(parent) = &self.parent
{
parent.sequence_id(&original_key)
} else {
self.database.read().sequence_id(&original_key)
}
}
},
},
}
}
pub fn set<T: Any + Send + Sync>(&self, key: &str, value: T) -> Result<Option<T>> {
match check_top_level_key(key) {
Ok(stripped_key) => self.root().set(stripped_key, value),
Err(original_key) => match check_local_key(original_key) {
Ok(local_key) => {
if self.contains_key(key) {
let old = self.database.read().update(local_key, value)?;
Ok(Some(old))
} else {
self.database.write().create(local_key, value)?;
Ok(None)
}
}
Err(original_key) => match self.remappings.find(original_key) {
RemappingTarget::BoardPointer(remapped_key) => self.parent.as_ref().map_or_else(
|| {
Err(Error::NoParent {
key: original_key.into(),
remapped: remapped_key.clone(),
})
},
|parent| parent.set(&remapped_key, value),
),
RemappingTarget::LocalPointer(remapped_key) => {
if self.contains_key(&remapped_key) {
let old = self
.database
.read()
.update(&remapped_key, value)?;
Ok(Some(old))
} else {
self.database
.write()
.create(remapped_key, value)?;
Ok(None)
}
}
RemappingTarget::RootPointer(remapped_key) => self.root().set(&remapped_key, value),
RemappingTarget::StringAssignment(assignment) => Err(Error::Assignment {
key: original_key.into(),
value: assignment,
}),
RemappingTarget::None(original_key) => {
if self.autoremap
&& let Some(parent) = &self.parent
{
parent.set(&original_key, value)
} else if self.contains_key(&original_key) {
let old = self
.database
.read()
.update(&original_key, value)?;
Ok(Some(old))
} else {
self.database
.write()
.create(original_key, value)?;
Ok(None)
}
}
},
},
}
}
pub fn try_get_mut_ref<T: Any + Send + Sync>(&self, key: &str) -> Result<EntryWriteGuard<T>> {
match check_top_level_key(key) {
Ok(stripped_key) => self.root().try_get_mut_ref(stripped_key),
Err(original_key) => match check_local_key(original_key) {
Ok(local_key) => self.database.read().try_get_mut_ref(local_key),
Err(original_key) => match self.remappings.find(original_key) {
RemappingTarget::BoardPointer(remapped_key) => self.parent.as_ref().map_or_else(
|| {
Err(Error::NoParent {
key: key.into(),
remapped: remapped_key.clone(),
})
},
|parent| parent.try_get_mut_ref(&remapped_key),
),
RemappingTarget::LocalPointer(remapped_key) => self
.database
.read()
.try_get_mut_ref(&remapped_key),
RemappingTarget::RootPointer(remapped_key) => self.root().try_get_mut_ref(&remapped_key),
RemappingTarget::StringAssignment(assignment) => Err(Error::Assignment {
key: original_key.into(),
value: assignment,
}),
RemappingTarget::None(original_key) => {
if self.autoremap
&& let Some(parent) = &self.parent
{
parent.try_get_mut_ref(&original_key)
} else {
self.database
.read()
.try_get_mut_ref(&original_key)
}
}
},
},
}
}
pub fn try_get_ref<T: Any + Send + Sync>(&self, key: &str) -> Result<EntryReadGuard<T>> {
match check_top_level_key(key) {
Ok(stripped_key) => self.root().try_get_ref(stripped_key),
Err(original_key) => match check_local_key(original_key) {
Ok(local_key) => self.database.read().try_get_ref(local_key),
Err(original_key) => match self.remappings.find(original_key) {
RemappingTarget::BoardPointer(remapped_key) => self.parent.as_ref().map_or_else(
|| {
Err(Error::NoParent {
key: key.into(),
remapped: remapped_key.clone(),
})
},
|parent| parent.try_get_ref(&remapped_key),
),
RemappingTarget::LocalPointer(remapped_key) => self.database.read().try_get_ref(&remapped_key),
RemappingTarget::RootPointer(remapped_key) => self.root().try_get_ref(&remapped_key),
RemappingTarget::StringAssignment(assignment) => Err(Error::Assignment {
key: original_key.into(),
value: assignment,
}),
RemappingTarget::None(original_key) => {
if self.autoremap
&& let Some(parent) = &self.parent
{
parent.get_ref(&original_key)
} else {
self.database.read().try_get_ref(&original_key)
}
}
},
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
const fn is_normal<T: Sized + Send + Sync>() {}
#[test]
const fn normal_types() {
is_normal::<DataboardInner>();
is_normal::<Databoard>();
}
}