use sealed::sealed;
use serde::Deserialize;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::collections::{BTreeMap, HashMap};
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::ops::Deref;
use std::slice::{Iter, IterMut};
use datasize::{data_size, DataSize};
use minicbor::{Decode, Encode};
use nanoid::nanoid;
use crate::annotationstore::AnnotationStore;
use crate::config::Configurable;
use crate::error::StamError;
use crate::substore::AnnotationSubStoreHandle;
use crate::types::*;
pub type Store<T> = Vec<Option<T>>;
const ID_LEN: usize = 21;
const ID_ALPHABET: [char; 62] = [
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B',
'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
'V', 'W', 'X', 'Y', 'Z',
];
#[derive(Debug, Clone, DataSize, Decode, Encode)]
pub struct IdMap<HandleType> {
#[n(0)] data: HashMap<String, HandleType>,
#[n(1)]
autoprefix: String,
#[n(2)]
resolve_temp_ids: bool,
}
impl<HandleType> Default for IdMap<HandleType>
where
HandleType: Handle,
{
fn default() -> Self {
Self {
data: HashMap::new(),
autoprefix: "_".to_string(),
resolve_temp_ids: true,
}
}
}
impl<HandleType> IdMap<HandleType>
where
HandleType: Handle,
{
pub(crate) fn new(autoprefix: String) -> Self {
Self {
autoprefix,
..Self::default()
}
}
pub(crate) fn with_resolve_temp_ids(mut self, value: bool) -> Self {
self.set_resolve_temp_ids(value);
self
}
pub(crate) fn set_resolve_temp_ids(&mut self, value: bool) {
self.resolve_temp_ids = value;
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn meminfo(&self) -> usize {
data_size(self)
}
pub fn shrink_to_fit(&mut self) {
self.data.shrink_to_fit();
}
pub(crate) fn reindex(&mut self, gaps: &[(HandleType, isize)]) {
for handle in self.data.values_mut() {
*handle = handle.reindex(gaps);
}
}
}
#[derive(Debug, Clone, DataSize, Decode, Encode)]
pub(crate) struct RelationMap<A, B> {
#[n(0)]
pub(crate) data: Vec<Vec<B>>,
#[n(1)]
_marker: PhantomData<A>, }
impl<A, B> Default for RelationMap<A, B>
where
A: Handle,
B: Handle,
{
fn default() -> Self {
Self {
data: Vec::new(),
_marker: PhantomData,
}
}
}
impl<A, B> RelationMap<A, B>
where
A: Handle,
B: Handle,
{
pub fn new() -> Self {
Self::default()
}
pub fn insert(&mut self, x: A, y: B) {
if x.as_usize() >= self.data.len() {
self.data.resize_with(x.as_usize() + 1, Default::default);
}
self.data[x.as_usize()].push(y);
}
pub fn remove(&mut self, x: A, y: B) {
if let Some(values) = self.data.get_mut(x.as_usize()) {
if let Some(pos) = values.iter().position(|z| *z == y) {
values.remove(pos); }
}
}
pub fn remove_all(&mut self, x: A) {
if x.as_usize() >= self.data.len() {
if let Some(values) = self.data.get_mut(x.as_usize()) {
values.clear();
}
}
}
pub fn get(&self, x: A) -> Option<&Vec<B>> {
self.data.get(x.as_usize())
}
pub fn totalcount(&self) -> usize {
let mut total = 0;
for v in self.data.iter() {
total += v.len();
}
total
}
pub fn meminfo(&self) -> usize {
data_size(self)
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn shrink_to_fit(&mut self, recursive: bool) {
if recursive {
for element in self.data.iter_mut() {
element.shrink_to_fit();
}
}
self.data.shrink_to_fit();
}
pub(crate) fn reindex(&self, gaps_a: &[(A, isize)], gaps_b: &[(B, isize)]) -> Self {
let mut newmap = Self::new();
for (handle_a, item) in self.data.iter().enumerate() {
let handle_a = A::new(handle_a).reindex(gaps_a);
for handle_b in item {
let handle_b = handle_b.reindex(gaps_b);
newmap.insert(handle_a, handle_b);
}
}
newmap
}
}
impl<A, B> Extend<(A, B)> for RelationMap<A, B>
where
A: Handle,
B: Handle,
{
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = (A, B)>,
{
for (x, y) in iter {
self.insert(x, y);
}
}
}
#[derive(Debug, Clone, DataSize, Decode, Encode)]
pub(crate) struct RelationBTreeMap<A, B>
where
A: Handle,
B: Handle,
{
#[n(0)]
pub(crate) data: BTreeMap<A, Vec<B>>,
}
impl<A, B> Default for RelationBTreeMap<A, B>
where
A: Handle,
B: Handle,
{
fn default() -> Self {
Self {
data: BTreeMap::new(),
}
}
}
impl<A, B> RelationBTreeMap<A, B>
where
A: Handle,
B: Handle,
{
pub fn new() -> Self {
Self::default()
}
pub fn insert(&mut self, x: A, y: B) {
if self.data.contains_key(&x) {
self.data.get_mut(&x).unwrap().push(y);
} else {
self.data.insert(x, vec![y]);
}
}
pub fn remove(&mut self, x: A, y: B) {
if let Some(values) = self.data.get_mut(&x) {
if let Some(pos) = values.iter().position(|z| *z == y) {
values.remove(pos); }
}
}
pub fn remove_all(&mut self, x: A) {
self.data.remove(&x);
}
pub fn get(&self, x: A) -> Option<&Vec<B>> {
self.data.get(&x)
}
pub fn totalcount(&self) -> usize {
let mut total = 0;
for v in self.data.values() {
total += v.len();
}
total
}
pub fn meminfo(&self) -> usize {
data_size(self)
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn shrink_to_fit(&mut self, recursive: bool) {
if recursive {
for element in self.data.values_mut() {
element.shrink_to_fit();
}
}
}
pub(crate) fn reindex(&self, gaps_a: &[(A, isize)], gaps_b: &[(B, isize)]) -> Self {
let mut newmap = Self::new();
for (handle_a, item) in self.data.iter() {
let handle_a = handle_a.reindex(gaps_a);
for handle_b in item {
let handle_b = handle_b.reindex(gaps_b);
newmap.insert(handle_a, handle_b);
}
}
newmap
}
}
impl<A, B> Extend<(A, B)> for RelationBTreeMap<A, B>
where
A: Handle,
B: Handle,
{
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = (A, B)>,
{
for (x, y) in iter {
self.insert(x, y);
}
}
}
#[derive(Debug, Clone, DataSize, Decode, Encode)]
pub(crate) struct TripleRelationMap<A, B, C> {
#[n(0)]
pub(crate) data: Vec<RelationMap<B, C>>,
#[n(1)]
_marker: PhantomData<A>,
}
impl<A, B, C> Default for TripleRelationMap<A, B, C> {
fn default() -> Self {
Self {
data: Vec::new(),
_marker: PhantomData,
}
}
}
impl<A, B, C> TripleRelationMap<A, B, C>
where
A: Handle,
B: Handle,
C: Handle,
{
pub fn new() -> Self {
Self::default()
}
pub fn insert(&mut self, x: A, y: B, z: C) {
if x.as_usize() >= self.data.len() {
self.data.resize_with(x.as_usize() + 1, Default::default);
}
self.data[x.as_usize()].insert(y, z);
}
pub fn get(&self, x: A, y: B) -> Option<&Vec<C>> {
if let Some(v) = self.data.get(x.as_usize()) {
v.get(y)
} else {
None
}
}
pub fn remove(&mut self, x: A, y: B, z: C) {
if let Some(map) = self.data.get_mut(x.as_usize()) {
map.remove(y, z);
}
}
pub fn remove_all(&mut self, x: A) {
if x.as_usize() >= self.data.len() {
self.data.remove(x.as_usize());
}
}
pub fn remove_second(&mut self, x: A, y: B) {
if let Some(v) = self.data.get_mut(x.as_usize()) {
v.remove_all(y)
}
}
pub fn totalcount(&self) -> usize {
let mut total = 0;
for v in self.data.iter() {
total += v.totalcount();
}
total
}
pub fn partialcount(&self) -> usize {
let mut total = 0;
for v in self.data.iter() {
total += v.len();
}
total
}
pub fn meminfo(&self) -> usize {
data_size(self)
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn shrink_to_fit(&mut self, recursive: bool) {
if recursive {
for element in self.data.iter_mut() {
element.shrink_to_fit(recursive);
}
}
self.data.shrink_to_fit();
}
pub(crate) fn reindex(
&self,
gaps_a: &[(A, isize)],
gaps_b: &[(B, isize)],
gaps_c: &[(C, isize)],
) -> Self {
let mut newmap = Self::new();
for (handle_a, inner) in self.data.iter().enumerate() {
let handle_a = A::new(handle_a).reindex(gaps_a);
for (handle_b, item) in inner.data.iter().enumerate() {
let handle_b = B::new(handle_b).reindex(gaps_b);
for handle_c in item {
let handle_c = handle_c.reindex(gaps_c);
newmap.insert(handle_a, handle_b, handle_c);
}
}
}
newmap
}
}
impl<A, B, C> Extend<(A, B, C)> for TripleRelationMap<A, B, C>
where
A: Handle,
B: Handle,
C: Handle,
{
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = (A, B, C)>,
{
for (x, y, z) in iter {
self.insert(x, y, z);
}
}
}
#[derive(Clone, Debug, DataSize, Encode, Decode)]
pub struct ExclusiveRelationMap<A, B>
where
A: Handle,
B: Handle,
{
#[n(0)]
data: BTreeMap<A, B>,
}
impl<A, B> Default for ExclusiveRelationMap<A, B>
where
A: Handle,
B: Handle,
{
fn default() -> Self {
Self::new()
}
}
impl<A, B> Extend<(A, B)> for ExclusiveRelationMap<A, B>
where
A: Handle,
B: Handle,
{
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = (A, B)>,
{
for (x, y) in iter {
self.insert(x, y);
}
}
}
impl<A, B> ExclusiveRelationMap<A, B>
where
A: Handle,
B: Handle,
{
pub fn new() -> Self {
Self {
data: BTreeMap::new(),
}
}
pub fn insert(&mut self, x: A, y: B) {
if self.data.contains_key(&x) {
if let Some(entry) = self.data.get_mut(&x) {
*entry = y;
}
} else {
self.data.insert(x, y);
}
}
pub fn remove_all(&mut self, x: A) {
self.data.remove(&x);
}
pub fn get(&self, x: A) -> Option<B> {
self.data.get(&x).copied()
}
pub fn meminfo(&self) -> usize {
data_size(self)
}
pub fn len(&self) -> usize {
self.data.len()
}
}
#[sealed(pub(crate))] pub trait Storable: PartialEq + TypeInfo + Debug + Sized {
type HandleType: Handle;
type StoreHandleType: Copy + Ord + Debug;
type FullHandleType: Copy + Ord + Debug;
type StoreType: StoreFor<Self>;
fn fullhandle(parent: Self::StoreHandleType, handle: Self::HandleType) -> Self::FullHandleType;
fn handle(&self) -> Option<Self::HandleType> {
None
}
fn handle_or_err(&self) -> Result<Self::HandleType, StamError> {
self.handle().ok_or(StamError::Unbound(""))
}
fn id(&self) -> Option<&str> {
None
}
fn temp_id(&self) -> Result<String, StamError> {
Ok(format!(
"{}{}",
Self::temp_id_prefix(),
self.handle_or_err()?.as_usize()
))
}
fn carries_id() -> bool;
fn as_resultitem<'store>(
&'store self,
store: &'store Self::StoreType,
rootstore: &'store AnnotationStore,
) -> ResultItem<'store, Self>
where
Self: Sized,
{
ResultItem::new(self, store, rootstore)
}
fn with_handle(self, _handle: <Self as Storable>::HandleType) -> Self {
self
}
fn generate_id(self, idmap: Option<&mut IdMap<Self::HandleType>>) -> Self
where
Self: Sized,
{
if let Some(intid) = self.handle() {
if let Some(idmap) = idmap {
loop {
let id = generate_id(&idmap.autoprefix, "");
let id_copy = id.clone();
if idmap.data.insert(id, intid).is_none() {
return self.with_id(id_copy);
}
}
}
}
self.with_id(generate_id("X", ""))
}
#[allow(unused_variables)]
fn with_id(self, id: impl Into<String>) -> Self
where
Self: Sized,
{
if Self::carries_id() {
unimplemented!("with_id() not implemented");
}
self
}
fn merge(&mut self, other: Self) -> Result<(), StamError>;
fn unbind(self) -> Self;
}
#[sealed(pub(crate))] pub trait StoreFor<T: Storable>: Configurable + private::StoreCallbacks<T> {
fn store(&self) -> &Store<T>;
fn store_mut(&mut self) -> &mut Store<T>;
fn idmap(&self) -> Option<&IdMap<T::HandleType>> {
None
}
fn idmap_mut(&mut self) -> Option<&mut IdMap<T::HandleType>> {
None
}
fn store_typeinfo() -> &'static str;
fn insert(&mut self, mut item: T) -> Result<T::HandleType, StamError> {
debug(self.config(), || {
format!("StoreFor<{}>.insert: new item", Self::store_typeinfo())
});
let handle = if let Some(intid) = item.handle() {
intid
} else {
let intid = self.next_handle();
if item.handle().is_some() {
return Err(StamError::AlreadyBound("bind()"));
} else {
item = item.with_handle(self.next_handle());
}
intid
};
if T::carries_id() {
if let Some(id) = item.id() {
if self.has(id) {
let existing_item = self.get(id).unwrap();
if *existing_item == item {
return Ok(existing_item.handle().unwrap());
}
if self.config().merge {
let existing_item = self.get_mut(id).unwrap();
existing_item.merge(item)?;
return Ok(existing_item.handle().unwrap());
} else {
return Err(StamError::DuplicateIdError(
id.to_string(),
Self::store_typeinfo(),
));
}
}
self.idmap_mut().map(|idmap| {
idmap.data.insert(id.to_string(), item.handle().unwrap())
});
debug(self.config(), || {
format!(
"StoreFor<{}>.insert: ^--- id={:?}",
Self::store_typeinfo(),
id
)
});
} else if self.config().generate_ids {
item = item.generate_id(self.idmap_mut());
debug(self.config(), || {
format!(
"StoreFor<{}>.insert: ^--- autogenerated id {}",
Self::store_typeinfo(),
item.id().unwrap(),
)
});
}
}
self.preinsert(&mut item)?;
self.store_mut().push(Some(item));
self.inserted(handle)?;
debug(self.config(), || {
format!(
"StoreFor<{}>.insert: ^--- {:?} (insertion complete now)",
Self::store_typeinfo(),
handle
)
});
assert_eq!(handle, T::HandleType::new(self.store().len() - 1), "sanity check to ensure no item can determine its own internal id that does not correspond with what's allocated
");
Ok(handle)
}
fn with_item(mut self, item: T) -> Result<Self, StamError>
where
Self: Sized,
{
self.insert(item)?;
Ok(self)
}
#[inline]
fn has(&self, item: impl Request<T>) -> bool {
if let Some(handle) = item.to_handle(self) {
self.store().get(handle.as_usize()).is_some()
} else {
false
}
}
#[inline]
unsafe fn get_unchecked(&self, handle: T::HandleType) -> Option<&T> {
self.store().get_unchecked(handle.as_usize()).as_ref()
}
#[inline]
fn get(&self, item: impl Request<T>) -> Result<&T, StamError> {
if let Some(handle) = item.to_handle(self) {
if let Some(Some(item)) = self.store().get(handle.as_usize()) {
return Ok(item);
}
}
Err(StamError::HandleError(Self::store_typeinfo()))
}
fn get_mut(&mut self, item: impl Request<T>) -> Result<&mut T, StamError> {
if let Some(handle) = item.to_handle(self) {
if let Some(Some(item)) = self.store_mut().get_mut(handle.as_usize()) {
return Ok(item);
}
}
Err(StamError::HandleError(Self::store_typeinfo()))
}
fn remove(&mut self, item: impl Request<T>) -> Result<(), StamError> {
if let Some(handle) = item.to_handle(self) {
self.preremove(handle)?;
if let Some(Some(item)) = self.store().get(handle.as_usize()) {
let id: Option<String> = item.id().map(|x| x.to_string());
if let Some(id) = id {
if let Some(idmap) = self.idmap_mut() {
idmap.data.remove(id.as_str());
}
}
} else {
return Err(StamError::HandleError(
"Unable to remove non-existing handle",
));
}
let item = self.store_mut().get_mut(handle.as_usize()).unwrap();
*item = None;
Ok(())
} else {
Err(StamError::HandleError(Self::store_typeinfo()))
}
}
fn resolve_id(&self, id: &str) -> Result<T::HandleType, StamError> {
if let Some(idmap) = self.idmap() {
if idmap.resolve_temp_ids {
if let Some(handle) = resolve_temp_id(id) {
return Ok(T::HandleType::new(handle));
}
}
if let Some(handle) = idmap.data.get(id) {
Ok(*handle)
} else {
Err(StamError::IdNotFoundError(
id.to_string(),
Self::store_typeinfo(),
))
}
} else {
Err(StamError::NoIdError(Self::store_typeinfo()))
}
}
#[inline]
fn iter<'a>(&'a self) -> StoreIter<'a, T>
where
T: Storable<StoreType = Self>,
{
StoreIter {
iter: self.store().iter(),
count: 0,
len: self.store().len(),
}
}
fn iter_mut<'a>(&'a mut self) -> StoreIterMut<'a, T> {
let len = self.store().len();
StoreIterMut {
iter: self.store_mut().iter_mut(),
count: 0,
len,
}
}
fn next_handle(&self) -> T::HandleType {
T::HandleType::new(self.store().len()) }
fn last_handle(&self) -> T::HandleType {
T::HandleType::new(self.store().len() - 1)
}
}
pub(crate) mod private {
pub trait StoreCallbacks<T: crate::store::Storable> {
#[allow(unused_variables)]
#[doc(hidden)]
fn preinsert(&self, item: &mut T) -> Result<(), crate::error::StamError> {
Ok(())
}
#[allow(unused_variables)]
#[doc(hidden)]
fn inserted(&mut self, handle: T::HandleType) -> Result<(), crate::error::StamError> {
Ok(())
}
#[allow(unused_variables)]
#[doc(hidden)]
fn preremove(&mut self, handle: T::HandleType) -> Result<(), crate::error::StamError> {
Ok(())
}
}
}
pub(crate) trait WrappableStore<T: Storable>: StoreFor<T> {
fn wrap_store<'a>(
&'a self,
substore: Option<AnnotationSubStoreHandle>,
) -> WrappedStore<'a, T, Self>
where
Self: Sized,
{
WrappedStore {
store: self.store(),
parent: self,
substore,
}
}
}
pub(crate) trait ReindexStore<T>
where
T: Storable,
{
fn gaps(&self) -> Vec<(T::HandleType, isize)>;
fn reindex(self, gaps: &[(T::HandleType, isize)]) -> Self;
}
impl<T> ReindexStore<T> for Vec<Option<T>>
where
T: Storable,
{
fn gaps(&self) -> Vec<(T::HandleType, isize)> {
let mut gaps = Vec::new();
let mut gapsize: isize = 0;
for item in self.iter() {
if item.is_none() {
gapsize -= 1;
} else if gapsize != 0 {
let handle = item.as_ref().unwrap().handle().expect("must have handle");
gaps.push((handle, gapsize));
gapsize = 0;
}
}
gaps
}
fn reindex(self, gaps: &[(T::HandleType, isize)]) -> Self {
if !gaps.is_empty() {
let totaldelta: isize = gaps.iter().map(|x| x.1).sum();
let newsize: usize = (self.len() as isize + totaldelta) as usize;
if newsize == 0 {
return Vec::new();
}
let mut newstore: Vec<Option<T>> = Vec::with_capacity(newsize);
for item in self {
if let Some(mut item) = item {
let handle = item.handle().expect("handle must exist");
let newhandle = handle.reindex(gaps); item = item.with_handle(newhandle);
newstore.push(Some(item));
}
}
return newstore;
}
self
}
}
pub struct StoreIter<'store, T>
where
T: Storable,
{
iter: Iter<'store, Option<T>>,
count: usize,
len: usize,
}
impl<'store, T> Iterator for StoreIter<'store, T>
where
T: Storable,
{
type Item = &'store T;
fn next(&mut self) -> Option<Self::Item> {
self.count += 1;
loop {
match self.iter.next() {
Some(Some(item)) => return Some(item),
Some(None) => continue,
None => return None,
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let l = self.len - self.count;
(l, Some(l))
}
}
pub struct StoreIterMut<'a, T> {
iter: IterMut<'a, Option<T>>,
count: usize,
len: usize,
}
impl<'a, T> Iterator for StoreIterMut<'a, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
self.count += 1;
loop {
match self.iter.next() {
Some(Some(item)) => return Some(item),
Some(None) => continue,
None => return None,
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let l = self.len - self.count;
(l, Some(l))
}
}
pub struct ResultItem<'store, T>
where
T: Storable,
{
item: &'store T,
store: &'store T::StoreType,
rootstore: Option<&'store AnnotationStore>,
}
#[sealed(pub(crate))] impl<'store, T> TypeInfo for ResultItem<'store, T>
where
T: Storable + TypeInfo,
{
fn typeinfo() -> Type {
T::typeinfo()
}
}
impl<'store, T> Debug for ResultItem<'store, T>
where
T: Storable,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ResultItem")
.field("item", &self.item)
.finish()
}
}
impl<'store, T> Clone for ResultItem<'store, T>
where
T: Storable + Clone,
{
fn clone(&self) -> Self {
Self {
item: self.item,
store: self.store,
rootstore: self.rootstore,
}
}
}
impl<'store, T> PartialEq for ResultItem<'store, T>
where
T: Storable,
{
fn eq(&self, other: &Self) -> bool {
self.handle() == other.handle()
}
}
impl<'store, T> Eq for ResultItem<'store, T> where T: Storable {}
impl<'store, T> Hash for ResultItem<'store, T>
where
T: Storable,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.handle().hash(state)
}
}
impl<'store, T> PartialOrd for ResultItem<'store, T>
where
T: Storable,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.handle().cmp(&other.handle()))
}
}
impl<'store, T> Ord for ResultItem<'store, T>
where
T: Storable,
{
fn cmp(&self, other: &Self) -> Ordering {
self.handle().cmp(&other.handle())
}
}
pub trait FullHandle<T>
where
T: Storable,
{
fn fullhandle(&self) -> T::FullHandleType;
}
impl<'store, T> ResultItem<'store, T>
where
T: Storable,
{
pub(crate) fn new(
item: &'store T,
store: &'store T::StoreType,
rootstore: &'store AnnotationStore,
) -> Self {
if item.handle().is_none() {
panic!("can't wrap unbound items");
}
Self {
item,
store,
rootstore: Some(rootstore),
}
}
pub(crate) fn new_partial(item: &'store T, store: &'store T::StoreType) -> Self {
if item.handle().is_none() {
panic!("can't wrap unbound items");
}
Self {
item,
store,
rootstore: None,
}
}
pub fn store(&self) -> &'store T::StoreType {
self.store
}
pub fn rootstore(&self) -> &'store AnnotationStore {
self.rootstore
.expect("Got a partial ResultItem, unable to get root annotationstore! This should not happen in the public API.")
}
#[inline]
pub fn as_ref(&self) -> &'store T {
self.item
}
#[inline]
pub fn handle(&self) -> T::HandleType {
self.item
.handle()
.expect("handle was already guaranteed for ResultItem, this should always work")
}
#[inline]
pub fn id(&self) -> Option<&'store str> {
self.item.id()
}
}
pub trait StamResult<T>
where
T: TypeInfo,
{
fn or_fail(self) -> Result<T, StamError>;
fn or_fail_for_id(self, id: &str) -> Result<T, StamError>;
fn or_fail_with<'a>(self, msg: Cow<'a, str>) -> Result<T, StamError>;
}
impl<'store, T> StamResult<T> for Option<T>
where
T: TypeInfo,
{
fn or_fail(self) -> Result<T, StamError> {
match self {
Some(item) => Ok(item),
None => Err(StamError::NotFoundError(
T::typeinfo(),
"Expected a result, got nothing".into(),
)),
}
}
fn or_fail_for_id(self, id: &str) -> Result<T, StamError> {
match self {
Some(item) => Ok(item),
None => Err(StamError::NotFoundError(T::typeinfo(), id.to_string())),
}
}
fn or_fail_with<'a>(self, msg: Cow<'a, str>) -> Result<T, StamError> {
match self {
Some(item) => Ok(item),
None => Err(StamError::NotFoundError(T::typeinfo(), msg.to_string())),
}
}
}
#[sealed]
impl<T> TypeInfo for Option<ResultItem<'_, T>>
where
T: Storable,
{
fn typeinfo() -> Type {
T::typeinfo()
}
}
pub(crate) struct WrappedStore<'a, T, S: StoreFor<T>>
where
T: Storable,
S: Sized,
{
pub(crate) store: &'a Store<T>,
pub(crate) parent: &'a S,
pub(crate) substore: Option<AnnotationSubStoreHandle>,
}
impl<'a, T, S> Deref for WrappedStore<'a, T, S>
where
T: Storable,
S: StoreFor<T>,
{
type Target = Store<T>;
fn deref(&self) -> &Self::Target {
self.store
}
}
#[derive(Debug, Deserialize)]
#[serde(untagged)]
pub enum BuildItem<'a, T>
where
T: Storable,
{
Id(String),
#[serde(skip)]
IdRef(&'a str),
#[serde(skip)]
Ref(&'a T),
#[serde(skip)]
Handle(T::HandleType),
#[serde(skip)]
None,
}
impl<'a, T> Clone for BuildItem<'a, T>
where
T: Storable,
{
fn clone(&self) -> Self {
match self {
Self::Id(s) => Self::Id(s.clone()),
Self::IdRef(s) => Self::Id(s.to_string()),
Self::Ref(r) => Self::Ref(*r),
Self::Handle(h) => Self::Handle(*h),
Self::None => Self::None,
}
}
}
impl<'a, T> Default for BuildItem<'a, T>
where
T: Storable,
{
fn default() -> Self {
Self::None
}
}
impl<'a, T> PartialEq for BuildItem<'a, T>
where
T: Storable,
{
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Handle(x), Self::Handle(y)) => x == y,
(Self::Id(x), Self::Id(y)) => x == y,
(Self::IdRef(x), Self::IdRef(y)) => x == y,
(Self::Id(x), Self::IdRef(y)) => x.as_str() == *y,
(Self::IdRef(x), Self::Id(y)) => *x == y.as_str(),
(Self::Ref(x), Self::Ref(y)) => x == y,
(Self::Ref(x), Self::Id(y)) => x.id() == Some(y.as_str()),
(Self::Ref(x), Self::IdRef(y)) => x.id() == Some(y),
(Self::Id(x), Self::Ref(y)) => Some(x.as_str()) == y.id(),
(Self::IdRef(x), Self::Ref(y)) => Some(*x) == y.id(),
_ => false,
}
}
}
impl<'a, T> BuildItem<'a, T>
where
T: Storable,
{
pub fn is_handle(&self) -> bool {
matches!(self, Self::Handle(_))
}
pub fn is_id(&self) -> bool {
match self {
Self::Id(_) => true,
Self::IdRef(_) => true,
_ => false,
}
}
pub fn is_none(&self) -> bool {
matches!(self, Self::None)
}
pub fn is_some(&self) -> bool {
!matches!(self, Self::None)
}
pub(crate) fn error(&self, contextmsg: &'static str) -> StamError {
match self {
Self::Handle(_) => StamError::HandleError(contextmsg),
Self::Id(id) => StamError::IdNotFoundError(id.to_string(), contextmsg),
Self::IdRef(id) => StamError::IdNotFoundError(id.to_string(), contextmsg),
Self::Ref(instance) => StamError::IdNotFoundError(
instance.id().unwrap_or("(no id)").to_string(),
contextmsg,
),
Self::None => StamError::Unbound("Supplied AnyId is not bound to anything!"),
}
}
pub fn to_string(self) -> Option<String> {
if let Self::Id(s) = self {
Some(s)
} else if let Self::IdRef(s) = self {
Some(s.to_string())
} else {
None
}
}
pub fn as_str<'slf>(&'slf self) -> Option<&'slf str> {
if let Self::Id(s) = self {
Some(s.as_str())
} else if let Self::IdRef(s) = self {
Some(s)
} else {
None
}
}
}
pub trait Request<T>
where
T: Storable,
Self: Sized,
{
fn to_handle<'store, S>(&self, store: &'store S) -> Option<T::HandleType>
where
S: StoreFor<T>;
fn requested_id(&self) -> Option<&str> {
None
}
fn requested_id_owned(self) -> Option<String> {
None
}
fn requested_handle(&self) -> Option<T::HandleType> {
None
}
fn any(&self) -> bool {
false
}
}
impl<'a, T> Request<T> for &'a str
where
T: Storable,
{
fn to_handle<'store, S>(&self, store: &'store S) -> Option<T::HandleType>
where
S: StoreFor<T>,
{
store.resolve_id(self).ok()
}
fn requested_id(&self) -> Option<&'a str> {
Some(self)
}
fn requested_id_owned(self) -> Option<String> {
Some(self.to_string())
}
fn any(&self) -> bool {
self.is_empty()
}
}
impl<'a, T> Request<T> for bool
where
T: Storable,
{
fn to_handle<'store, S>(&self, _store: &'store S) -> Option<T::HandleType>
where
S: StoreFor<T>,
{
None
}
fn any(&self) -> bool {
true
}
}
impl<'a, T> Request<T> for String
where
T: Storable,
{
fn to_handle<'store, S>(&self, store: &'store S) -> Option<T::HandleType>
where
S: StoreFor<T>,
{
store.resolve_id(self.as_str()).ok()
}
fn requested_id(&self) -> Option<&str> {
Some(self.as_str())
}
fn requested_id_owned(self) -> Option<String> {
Some(self)
}
fn any(&self) -> bool {
self.is_empty()
}
}
impl<'a, T> Request<T> for ResultItem<'a, T>
where
T: Storable,
{
fn to_handle<'store, S>(&self, _store: &'store S) -> Option<T::HandleType>
where
S: StoreFor<T>,
{
Some(self.handle())
}
}
impl<'a, T> Request<T> for &ResultItem<'a, T>
where
T: Storable,
{
fn to_handle<'store, S>(&self, _store: &'store S) -> Option<T::HandleType>
where
S: StoreFor<T>,
{
Some(self.handle())
}
}
impl<'a, T> Request<T> for BuildItem<'a, T>
where
T: Storable,
{
fn to_handle<'store, S>(&self, store: &'store S) -> Option<T::HandleType>
where
S: StoreFor<T>,
{
match self {
BuildItem::Id(id) => store.resolve_id(id.as_str()).ok(),
BuildItem::IdRef(id) => store.resolve_id(id).ok(),
BuildItem::Handle(handle) => Some(*handle),
BuildItem::Ref(instance) => instance.handle(),
BuildItem::None => None,
}
}
}
impl<'a, T> Request<T> for &BuildItem<'a, T>
where
T: Storable,
{
fn to_handle<'store, S>(&self, store: &'store S) -> Option<T::HandleType>
where
S: StoreFor<T>,
{
match self {
BuildItem::Id(id) => store.resolve_id(id.as_str()).ok(),
BuildItem::IdRef(id) => store.resolve_id(id).ok(),
BuildItem::Handle(handle) => Some(*handle),
BuildItem::Ref(instance) => instance.handle(),
BuildItem::None => None,
}
}
}
impl<'a, T> From<&'a str> for BuildItem<'a, T>
where
T: Storable,
{
fn from(id: &'a str) -> Self {
if id.is_empty() {
Self::None
} else {
Self::IdRef(id)
}
}
}
impl<'a, T> From<Option<&'a str>> for BuildItem<'a, T>
where
T: Storable,
{
fn from(id: Option<&'a str>) -> Self {
if let Some(id) = id {
if id.is_empty() {
Self::None
} else {
Self::IdRef(id)
}
} else {
Self::None
}
}
}
impl<'a, T> From<String> for BuildItem<'a, T>
where
T: Storable,
{
fn from(id: String) -> Self {
if id.is_empty() {
Self::None
} else {
Self::Id(id)
}
}
}
impl<'a, T> From<&'a String> for BuildItem<'a, T>
where
T: Storable,
{
fn from(id: &'a String) -> Self {
if id.is_empty() {
Self::None
} else {
Self::IdRef(id.as_str())
}
}
}
impl<'a, T> From<Option<String>> for BuildItem<'a, T>
where
T: Storable,
{
fn from(id: Option<String>) -> Self {
if let Some(id) = id {
if id.is_empty() {
Self::None
} else {
Self::Id(id)
}
} else {
Self::None
}
}
}
impl<'a, T> From<&'a T> for BuildItem<'a, T>
where
T: Storable,
{
fn from(instance: &'a T) -> Self {
Self::Ref(instance)
}
}
impl<'a, T> From<usize> for BuildItem<'a, T>
where
T: Storable,
{
fn from(handle: usize) -> Self {
Self::Handle(T::HandleType::new(handle))
}
}
impl<'a, T> From<Option<usize>> for BuildItem<'a, T>
where
T: Storable,
{
fn from(handle: Option<usize>) -> Self {
if let Some(handle) = handle {
Self::Handle(T::HandleType::new(handle))
} else {
Self::None
}
}
}
impl<'a, T> From<&ResultItem<'a, T>> for BuildItem<'a, T>
where
T: Storable,
{
fn from(result: &ResultItem<'a, T>) -> Self {
Self::Ref(result.as_ref())
}
}
impl<'a, T> PartialEq<&str> for BuildItem<'a, T>
where
T: Storable,
{
fn eq(&self, other: &&str) -> bool {
match self {
Self::Id(v) => v.as_str() == *other,
_ => false,
}
}
}
impl<'a, T> PartialEq<str> for BuildItem<'a, T>
where
T: Storable,
{
fn eq(&self, other: &str) -> bool {
match self {
Self::Id(v) => v.as_str() == other,
Self::IdRef(v) => *v == other,
Self::Ref(r) => r.id() == Some(other),
_ => false,
}
}
}
impl<'a, T> PartialEq<String> for BuildItem<'a, T>
where
T: Storable,
{
fn eq(&self, other: &String) -> bool {
match self {
Self::Id(v) => v == other,
Self::IdRef(v) => *v == other.as_str(),
Self::Ref(r) => r.id() == Some(other),
_ => false,
}
}
}
pub(crate) fn resolve_temp_id(id: &str) -> Option<usize> {
let mut iter = id.chars();
if let Some('!') = iter.next() {
if let Some(x) = iter.next() {
if !x.is_uppercase() {
return None;
}
return Some(id[2..].parse().ok()?);
}
}
None
}
pub fn generate_id(prefix: &str, suffix: &str) -> String {
format!("{}{}{}", prefix, nanoid!(ID_LEN, &ID_ALPHABET), suffix)
}
#[derive(Clone, Debug)]
pub enum IdStrategy {
AddSuffix(String),
AddRandomSuffix,
AddPrefix(String),
UpdateVersion,
Replace(String),
ReplaceRandom { prefix: String, suffix: String },
}
impl Default for IdStrategy {
fn default() -> Self {
Self::UpdateVersion
}
}
pub fn regenerate_id<'a>(id: &'a str, strategy: &'a IdStrategy) -> String {
match strategy {
IdStrategy::AddSuffix(s) => {
format!("{}{}", id, s)
}
IdStrategy::AddRandomSuffix => {
format!("{}{}", id, nanoid!(ID_LEN, &ID_ALPHABET))
}
IdStrategy::AddPrefix(s) => {
format!("{}{}", s, id)
}
IdStrategy::Replace(s) => s.clone(),
IdStrategy::ReplaceRandom { prefix, suffix } => generate_id(prefix, suffix),
IdStrategy::UpdateVersion => {
if let Some(pos) = id.rfind(|c: char| c.is_ascii_punctuation()) {
let mut version = &id[pos + 1..];
if version.chars().next() == Some('v') {
version = &id[pos + 2..];
if let Ok(mut version) = version.parse::<usize>() {
version += 1;
return format!("{}v{}", &id[..pos + 1], version);
}
}
}
format!("{}/v2", &id)
}
}
}
impl TryFrom<&str> for IdStrategy {
type Error = StamError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
if let Some(pos) = value.find("=") {
let strategy = &value[0..pos];
if pos + 1 >= value.len() {
Err(StamError::DeserializationError(format!(
"IdStrategy expects value after = "
)))
} else {
let value = &value[pos + 1..];
match strategy {
"suffix" | "addsuffix" => Ok(Self::AddSuffix(value.to_string())),
"prefix" | "addprefix" => Ok(Self::AddPrefix(value.to_string())),
"replace" => Ok(Self::Replace(value.to_string())),
"replacerandom" => {
let (prefix, suffix) = if let Some(pos) = value.find(";") {
(value[0..pos].to_string(), value[pos + 1..].to_string())
} else {
(value.to_string(), String::new())
};
Ok(Self::ReplaceRandom { prefix, suffix })
}
_ => Err(StamError::DeserializationError(format!(
"Invalid IdStrategy: {}",
strategy
))),
}
}
} else {
match value {
"version" | "updateversion" => Ok(Self::UpdateVersion),
"random" | "randomsuffix" => Ok(Self::AddRandomSuffix),
_ => Err(StamError::DeserializationError(format!(
"Invalid IdStrategy: {}",
value
))),
}
}
}
}