use std::{
collections::{HashMap, HashSet},
mem,
};
use tari_bor::Value;
use tari_engine_types::indexed_value::{IndexedValue, IndexedValueError};
use tari_ootle_transaction::args::{WorkspaceId, WorkspaceOffsetId};
use tari_template_lib::models::ProofId;
use crate::runtime::RuntimeError;
#[derive(Debug, thiserror::Error)]
pub enum WorkspaceError {
#[error("Indexed value error: {0}")]
IndexedValueError(#[from] IndexedValueError),
#[error("Workspace ID {0} already exists in the workspace")]
WorkspaceIdAlreadyExists(WorkspaceId),
}
#[derive(Debug, Clone, Default)]
pub struct Workspace {
items: HashMap<WorkspaceId, IndexedValue>,
proofs: HashSet<ProofId>,
}
impl Workspace {
pub fn get(&self, offset_id: WorkspaceOffsetId) -> Result<Option<&Value>, RuntimeError> {
let Some(value) = self.items.get(&offset_id.id()) else {
return Ok(None);
};
let Some(offset) = offset_id.offset() else {
return Ok(Some(value.value()));
};
match value.value() {
Value::Array(items) => Ok(items.get(offset)),
Value::Map(items) => Ok(items.get(offset).map(|(_, v)| v)),
_ => Ok(None),
}
}
pub fn insert(&mut self, id: WorkspaceId, value: IndexedValue) -> Result<(), WorkspaceError> {
if !value.proof_ids().is_empty() {
self.proofs.extend(value.proof_ids().iter().copied());
}
if self.items.contains_key(&id) {
return Err(WorkspaceError::WorkspaceIdAlreadyExists(id));
}
self.items.insert(id, value);
Ok(())
}
pub fn drain_all_proofs(&mut self) -> HashSet<ProofId> {
mem::take(&mut self.proofs)
}
pub fn clear_items(&mut self) {
self.items.clear();
}
pub fn all_ids_iter(&self) -> impl Iterator<Item = WorkspaceId> + '_ {
self.items.keys().copied()
}
}
#[cfg(test)]
mod tests {
use tari_engine_types::indexed_value::IndexedValue;
use super::*;
#[test]
fn tuples() {
let tuple = ("Foo", 32);
let encoded_tuple = IndexedValue::from_type(&tuple).unwrap();
let mut workspace = Workspace::default();
workspace.insert(1, encoded_tuple.clone()).unwrap();
let value = workspace.get(WorkspaceOffsetId::new(1)).unwrap().unwrap();
assert_eq!(value, encoded_tuple.value());
let expected = IndexedValue::from_type(&tuple.0).unwrap();
let value = workspace
.get(WorkspaceOffsetId::new(1).with_offset(0))
.unwrap()
.unwrap();
assert_eq!(value, expected.value());
let expected = IndexedValue::from_type(&tuple.1).unwrap();
let value = workspace
.get(WorkspaceOffsetId::new(1).with_offset(1))
.unwrap()
.unwrap();
assert_eq!(value, expected.value());
}
}