use std::borrow::Cow;
use std::marker::PhantomData;
use std::slice::Iter;
use datasize::DataSize;
use minicbor::{Decode, Encode};
use sealed::sealed;
use serde::ser::{SerializeSeq, SerializeStruct, Serializer};
use serde::{Deserialize, Serialize};
use crate::annotationdata::{AnnotationData, AnnotationDataBuilder, AnnotationDataHandle};
use crate::annotationdataset::{AnnotationDataSet, AnnotationDataSetHandle};
use crate::annotationstore::AnnotationStore;
use crate::config::{Config, Configurable};
use crate::datakey::DataKey;
use crate::datavalue::DataValue;
use crate::error::*;
use crate::file::*;
use crate::resources::{TextResource, TextResourceHandle};
use crate::selector::{
OffsetMode, Selector, SelectorBuilder, SelectorIter, SelfSelector, WrappedSelector,
};
use crate::store::private::StoreCallbacks;
use crate::store::*;
use crate::types::*;
use smallvec::SmallVec;
type DataVec = Vec<(AnnotationDataSetHandle, AnnotationDataHandle)>;
#[derive(Clone, Debug, DataSize, Encode, Decode)]
pub struct Annotation {
#[n(0)] intid: Option<AnnotationHandle>,
#[n(1)]
pub(crate) id: Option<String>,
#[n(2)]
data: DataVec,
#[n(3)]
target: Selector, }
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, DataSize, Encode, Decode)]
#[cbor(transparent)]
pub struct AnnotationHandle(#[n(0)] u32);
#[sealed]
impl Handle for AnnotationHandle {
fn new(intid: usize) -> Self {
Self(intid as u32)
}
fn as_usize(&self) -> usize {
self.0 as usize
}
}
impl<'a> Request<Annotation> for AnnotationHandle {
fn to_handle<'store, S>(&self, _store: &'store S) -> Option<AnnotationHandle>
where
S: StoreFor<Annotation>,
{
Some(*self)
}
}
impl<'a> From<&AnnotationHandle> for BuildItem<'a, Annotation> {
fn from(handle: &AnnotationHandle) -> Self {
BuildItem::Handle(*handle)
}
}
impl<'a> From<Option<&AnnotationHandle>> for BuildItem<'a, Annotation> {
fn from(handle: Option<&AnnotationHandle>) -> Self {
if let Some(handle) = handle {
BuildItem::Handle(*handle)
} else {
BuildItem::None
}
}
}
impl<'a> From<AnnotationHandle> for BuildItem<'a, Annotation> {
fn from(handle: AnnotationHandle) -> Self {
BuildItem::Handle(handle)
}
}
impl<'a> From<Option<AnnotationHandle>> for BuildItem<'a, Annotation> {
fn from(handle: Option<AnnotationHandle>) -> Self {
if let Some(handle) = handle {
BuildItem::Handle(handle)
} else {
BuildItem::None
}
}
}
#[sealed]
impl TypeInfo for Annotation {
fn typeinfo() -> Type {
Type::Annotation
}
}
#[sealed]
impl Storable for Annotation {
type HandleType = AnnotationHandle;
type StoreHandleType = ();
type FullHandleType = Self::HandleType;
type StoreType = AnnotationStore;
fn id(&self) -> Option<&str> {
self.id.as_deref()
}
fn handle(&self) -> Option<Self::HandleType> {
self.intid
}
fn with_handle(mut self, handle: Self::HandleType) -> Self {
self.intid = Some(handle);
self
}
fn carries_id() -> bool {
true
}
fn with_id(mut self, id: impl Into<String>) -> Self {
self.id = Some(id.into());
self
}
fn fullhandle(
_parenthandle: Self::StoreHandleType,
handle: Self::HandleType,
) -> Self::FullHandleType {
handle
}
fn merge(&mut self, _other: Self) -> Result<(), StamError> {
return Err(StamError::OtherError("Can not merge annotations"));
}
fn unbind(mut self) -> Self {
self.intid = None;
self
}
}
impl PartialEq<Annotation> for Annotation {
fn eq(&self, other: &Annotation) -> bool {
self.id.is_some()
&& self.id == other.id
&& self.target == other.target
&& self.data == other.data
}
}
#[derive(Deserialize, Debug)]
#[serde(tag = "Annotation")]
#[serde(from = "AnnotationJson")]
pub struct AnnotationBuilder<'a> {
pub(crate) id: BuildItem<'a, Annotation>,
pub(crate) data: Vec<AnnotationDataBuilder<'a>>,
pub(crate) target: Option<SelectorBuilder<'a>>,
}
impl<'a> Default for AnnotationBuilder<'a> {
fn default() -> Self {
Self {
id: BuildItem::None,
target: None,
data: Vec::new(),
}
}
}
impl Annotation {
pub fn to_json_string(&self, store: &AnnotationStore) -> Result<String, StamError> {
let wrapped: ResultItem<Self> = ResultItem::new_partial(self, store);
serde_json::to_string_pretty(&wrapped).map_err(|e| {
StamError::SerializationError(format!("Writing annotation to string: {}", e))
})
}
pub fn to_json_value(&self, store: &AnnotationStore) -> Result<serde_json::Value, StamError> {
let wrapped: ResultItem<Self> = ResultItem::new_partial(self, store);
serde_json::to_value(&wrapped)
.map_err(|e| StamError::SerializationError(format!("Producing Json Value: {}", e)))
}
}
impl<'a> AnnotationBuilder<'a> {
pub fn new() -> Self {
Self::default()
}
pub fn id(&'a self) -> Option<&'a str> {
match &self.id {
BuildItem::Id(id) => Some(id.as_str()),
BuildItem::IdRef(id) => Some(id),
_ => None,
}
}
pub fn handle(&self) -> Option<AnnotationHandle> {
match self.id {
BuildItem::Handle(handle) => Some(handle),
_ => None,
}
}
pub fn data(&self) -> &Vec<AnnotationDataBuilder<'a>> {
&self.data
}
pub fn target(&self) -> Option<&SelectorBuilder<'a>> {
self.target.as_ref()
}
pub fn with_id(mut self, id: impl Into<String>) -> Self {
self.id = BuildItem::Id(id.into());
self
}
pub fn with_handle(mut self, handle: AnnotationHandle) -> Self {
self.id = BuildItem::Handle(handle);
self
}
pub fn with_target(mut self, selector: SelectorBuilder<'a>) -> Self {
self.target = Some(selector);
self
}
pub fn with_data(
self,
dataset: impl Into<BuildItem<'a, AnnotationDataSet>>,
key: impl Into<BuildItem<'a, DataKey>>,
value: impl Into<DataValue>,
) -> Self {
self.with_data_builder(AnnotationDataBuilder {
dataset: dataset.into(),
key: key.into(),
value: value.into(),
..Default::default()
})
}
pub fn with_data_with_id(
self,
dataset: impl Into<BuildItem<'a, AnnotationDataSet>>,
key: impl Into<BuildItem<'a, DataKey>>,
value: impl Into<DataValue>,
id: impl Into<BuildItem<'a, AnnotationData>>,
) -> Self {
self.with_data_builder(AnnotationDataBuilder {
id: id.into(),
dataset: dataset.into(),
key: key.into(),
value: value.into(),
})
}
pub fn with_existing_data(
self,
dataset: impl Into<BuildItem<'a, AnnotationDataSet>>,
annotationdata: impl Into<BuildItem<'a, AnnotationData>>,
) -> Self {
self.with_data_builder(AnnotationDataBuilder {
id: annotationdata.into(),
dataset: dataset.into(),
..Default::default()
})
}
pub fn with_data_builder(mut self, builder: AnnotationDataBuilder<'a>) -> Self {
self.data.push(builder);
self
}
pub fn from_json_file(filename: &str, config: &Config) -> Result<Self, StamError> {
let reader = open_file_reader(filename, config)?;
let deserializer = &mut serde_json::Deserializer::from_reader(reader);
let result: Result<Self, _> = serde_path_to_error::deserialize(deserializer);
result.map_err(|e| {
StamError::JsonError(e, filename.to_string(), "Reading annotation from file")
})
}
pub fn from_json_str(string: &str) -> Result<Self, StamError> {
let deserializer = &mut serde_json::Deserializer::from_str(string);
let result: Result<Self, _> = serde_path_to_error::deserialize(deserializer);
result.map_err(|e| {
StamError::JsonError(e, string.to_string(), "Reading annotation from string")
})
}
}
impl<'a> Serialize for ResultItem<'a, Annotation> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("Annotation", 2)?;
state.serialize_field("@type", "Annotation")?;
if let Some(id) = self.id() {
state.serialize_field("@id", id)?;
} else {
state.serialize_field(
"@id",
&self.as_ref().temp_id().expect("temp_id must succeed"),
)?;
}
let target = WrappedSelector::new(&self.as_ref().target(), &self.store());
state.serialize_field("target", &target)?;
let wrappeddata = AnnotationDataRefSerializer { annotation: &self };
state.serialize_field("data", &wrappeddata)?;
state.end()
}
}
struct AnnotationDataRefSerializer<'a, 'b> {
annotation: &'b ResultItem<'a, Annotation>,
}
struct AnnotationDataRef<'a> {
id: Cow<'a, str>,
set: &'a str,
}
impl<'a> Serialize for AnnotationDataRef<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("AnnotationDataRef", 3)?;
state.serialize_field("@type", "AnnotationData")?;
state.serialize_field("@id", &self.id)?;
state.serialize_field("set", &self.set)?;
state.end()
}
}
impl<'a, 'b> Serialize for AnnotationDataRefSerializer<'a, 'b> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_seq(Some(self.annotation.as_ref().data.len()))?;
for (datasethandle, datahandle) in self.annotation.as_ref().data.iter() {
let store: &AnnotationStore = self.annotation.store();
let annotationset: &AnnotationDataSet = store
.get(*datasethandle)
.map_err(|e| serde::ser::Error::custom(format!("{}", e)))?;
let annotationdata: &AnnotationData = annotationset
.get(*datahandle)
.map_err(|e| serde::ser::Error::custom(format!("{}", e)))?;
seq.serialize_element(&AnnotationDataRef {
id: if let Some(id) = annotationdata.id() {
Cow::Borrowed(id)
} else {
Cow::Owned(annotationdata.temp_id().expect("temp_id must succeed"))
},
set: annotationset.id().ok_or_else(|| {
serde::ser::Error::custom(
"AnnotationDataSet must have a public ID if it is to be serialized",
)
})?,
})?;
}
seq.end()
}
}
impl AnnotationStore {
pub fn with_annotation(mut self, builder: AnnotationBuilder) -> Result<Self, StamError> {
self.annotate(builder)?;
Ok(self)
}
pub fn with_annotations<'a, I>(mut self, builders: I) -> Result<Self, StamError>
where
I: IntoIterator<Item = AnnotationBuilder<'a>>,
{
self.annotate_from_iter(builders)?;
Ok(self)
}
pub fn insert_data(
&mut self,
dataitem: AnnotationDataBuilder,
) -> Result<(AnnotationDataSetHandle, AnnotationDataHandle), StamError> {
debug(self.config(), || {
format!("AnnotationStore.insert_data: dataitem={:?}", dataitem)
});
let dataset: &mut AnnotationDataSet = if let Ok(dataset) = self.get_mut(&dataitem.dataset) {
dataset
} else {
let dataset_id: String = match dataitem.dataset {
BuildItem::Id(dataset_id) => dataset_id,
BuildItem::IdRef(dataset_id) => dataset_id.to_string(),
_ =>
{
"default-annotationset".into()
}
};
let inserted_intid =
self.insert(AnnotationDataSet::new(self.config().clone()).with_id(dataset_id))?;
self.get_mut(inserted_intid)
.expect("must exist after insertion")
};
let data_handle = dataset.insert_data(dataitem.id, dataitem.key, dataitem.value, true)?;
Ok((dataset.handle_or_err()?, data_handle))
}
pub fn annotate(&mut self, builder: AnnotationBuilder) -> Result<AnnotationHandle, StamError> {
debug(self.config(), || {
format!("AnnotationStore.annotate: builder={:?}", builder)
});
if builder.target.is_none() {
return Err(StamError::NoTarget("(AnnotationStore.annotate)"));
}
let target = self.selector(builder.target.unwrap()).map_err(|err| {
StamError::BuildError(
Box::new(err),
"Getting target selector failed (AnnotationStore.annotate)",
)
})?;
let mut data = DataVec::with_capacity(builder.data.len());
for dataitem in builder.data {
let (datasethandle, datahandle) = self.insert_data(dataitem).map_err(|err| {
StamError::BuildError(
Box::new(err),
"Inserting dataitem failed (AnnotationStore.annotate)",
)
})?;
data.push((datasethandle, datahandle));
}
let public_id: Option<String> = match builder.id {
BuildItem::Id(id) => Some(id),
_ => None,
};
self.insert(Annotation::new(public_id, target, data))
}
pub fn annotate_from_iter<'a, I>(
&mut self,
builders: I,
) -> Result<Vec<AnnotationHandle>, StamError>
where
I: IntoIterator<Item = AnnotationBuilder<'a>>,
{
let mut handles = Vec::new();
for builder in builders {
handles.push(self.annotate(builder)?);
}
Ok(handles)
}
pub fn reannotate(
&mut self,
builder: AnnotationBuilder,
data_mode: ReannotateMode,
) -> Result<AnnotationHandle, StamError> {
debug(self.config(), || {
format!("AnnotationStore.reannotate: builder={:?}", builder)
});
let annotation = if let Some(id) = builder.id() {
self.annotation(id)
} else if let Some(handle) = builder.handle() {
self.annotation(handle)
} else {
None
};
if let Some(annotation) = annotation {
let handle = annotation.handle();
let mut data = DataVec::with_capacity(builder.data.len());
for dataitem in builder.data {
let (datasethandle, datahandle) = self.insert_data(dataitem).map_err(|err| {
StamError::BuildError(
Box::new(err),
"Inserting dataitem failed (AnnotationStore.reannotate)",
)
})?;
data.push((datasethandle, datahandle));
}
let target: Option<Selector> = if builder.target.is_none() {
None
} else {
Some(self.selector(builder.target.unwrap()).map_err(|err| {
StamError::BuildError(
Box::new(err),
"Getting target selector failed (AnnotationStore.reannotate)",
)
})?)
};
let annotation = self.get_mut(handle)?;
if data_mode == ReannotateMode::Replace {
annotation.data = data;
} else if data_mode == ReannotateMode::Add {
annotation.data.extend(data.into_iter());
}
if let Some(target) = target {
annotation.target = target;
}
<AnnotationStore as StoreCallbacks<Annotation>>::inserted(self, handle)?;
Ok(handle)
} else {
self.annotate(builder)
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ReannotateMode {
Replace,
Add,
}
impl Default for ReannotateMode {
fn default() -> Self {
Self::Add
}
}
impl Annotation {
fn new(id: Option<String>, target: Selector, data: DataVec) -> Self {
Annotation {
id,
data,
target,
intid: None, }
}
pub fn data<'a>(&'a self) -> Iter<'a, (AnnotationDataSetHandle, AnnotationDataHandle)> {
self.data.iter()
}
pub fn raw_data(&self) -> &[(AnnotationDataSetHandle, AnnotationDataHandle)] {
&self.data
}
pub(crate) fn remove_data(&mut self, set: AnnotationDataSetHandle, data: AnnotationDataHandle) {
self.data.retain(|(s, d)| *s != set && *d != data);
}
pub fn data_by_index(
&self,
index: usize,
) -> Option<&(AnnotationDataSetHandle, AnnotationDataHandle)> {
self.data.get(index)
}
pub fn has_data(&self, set: AnnotationDataSetHandle, handle: AnnotationDataHandle) -> bool {
self.data.contains(&(set, handle))
}
pub(crate) fn add_data(&mut self, set: AnnotationDataSetHandle, handle: AnnotationDataHandle) {
self.data.push((set, handle));
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn target(&self) -> &Selector {
&self.target
}
}
#[derive(Deserialize)]
pub(crate) struct AnnotationJson<'a> {
#[serde(rename = "@id")]
id: Option<String>,
data: Vec<AnnotationDataBuilder<'a>>,
target: SelectorBuilder<'a>,
}
#[derive(Deserialize)]
pub(crate) struct AnnotationsJson<'a>(pub(crate) Vec<AnnotationJson<'a>>);
impl<'a> From<AnnotationJson<'a>> for AnnotationBuilder<'a> {
fn from(helper: AnnotationJson<'a>) -> Self {
Self {
id: helper.id.into(),
data: helper.data,
target: Some(helper.target),
}
}
}
impl SelfSelector for Annotation {
fn to_selector(&self) -> Result<Selector, StamError> {
if let Some(handle) = self.handle() {
if let (Some(res_handle), Some(tsel_handle)) = (
self.target().resource_handle(),
self.target().textselection_handle(),
) {
Ok(Selector::AnnotationSelector(
handle,
Some((res_handle, tsel_handle, OffsetMode::default())),
))
} else {
Ok(Selector::AnnotationSelector(handle, None))
}
} else {
Err(StamError::Unbound("Annotation::self_selector()"))
}
}
}
pub struct TargetIter<'a, T>
where
T: Storable,
{
pub(crate) iter: SelectorIter<'a>,
pub(crate) history: SmallVec<[T::HandleType; 3]>, pub(crate) _phantomdata: PhantomData<T>,
}
impl<'a, T> TargetIter<'a, T>
where
T: Storable,
{
pub fn new(iter: SelectorIter<'a>) -> Self {
Self {
iter,
history: SmallVec::new(),
_phantomdata: PhantomData,
}
}
}
impl<'a> Iterator for TargetIter<'a, TextResource> {
type Item = TextResourceHandle;
fn next(&mut self) -> Option<Self::Item> {
loop {
let selectoritem = self.iter.next();
if let Some(selectoritem) = selectoritem {
match selectoritem.as_ref() {
Selector::TextSelector(res_id, _, _)
| Selector::ResourceSelector(res_id)
| Selector::AnnotationSelector(_, Some((res_id, _, _))) => {
if self.history.contains(res_id) {
continue;
}
self.history.push(*res_id);
return Some(*res_id);
}
_ => continue,
}
} else {
return None;
}
}
}
}
impl<'a> Iterator for TargetIter<'a, AnnotationDataSet> {
type Item = AnnotationDataSetHandle;
fn next(&mut self) -> Option<Self::Item> {
loop {
let selectoritem = self.iter.next();
if let Some(selectoritem) = selectoritem {
match selectoritem.as_ref() {
Selector::DataSetSelector(set_id) => {
return Some(*set_id);
}
_ => continue,
}
} else {
return None;
}
}
}
}
impl<'a> Iterator for TargetIter<'a, Annotation> {
type Item = AnnotationHandle;
fn next(&mut self) -> Option<Self::Item> {
loop {
let selectoritem = self.iter.next();
if let Some(selectoritem) = selectoritem {
match selectoritem.as_ref() {
Selector::AnnotationSelector(a_id, _) => {
if self.iter.recurse_annotation {
if self.history.contains(a_id) {
continue;
}
self.history.push(*a_id);
}
return Some(*a_id);
}
_ => continue,
}
} else {
return None;
}
}
}
}