1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
//! interface to the knowledge base of an agent
use crate::{utils, Error, Result};
// _ __ _ _ ____
// | |/ /_ __ _____ _| | ___ __| | __ _ ___| __ ) __ _ ___ ___
// | ' /| '_ \ / _ \ \ /\ / / |/ _ \/ _` |/ _` |/ _ \ _ \ / _` / __|/ _ \
// | . \| | | | (_) \ V V /| | __/ (_| | (_| | __/ |_) | (_| \__ \ __/
// |_|\_\_| |_|\___/ \_/\_/ |_|\___|\__,_|\__, |\___|____/ \__,_|___/\___|
// |___/
/// Trait for the low level interface to the knowledge base
pub trait KnowledgeBase: Sync + Send + dyn_clone::DynClone + 'static
{
/// Insert data
fn insert_data(&self, collection: String, key: String, data: Vec<u8>) -> Result<()>;
/// Retrieve data
fn retrieve_data(&self, collection: String, key: String) -> Result<Vec<u8>>;
}
dyn_clone::clone_trait_object!(KnowledgeBase);
// _ __ _ _ ____ ___ _ __
// | |/ /_ __ _____ _| | ___ __| | __ _ ___| __ ) __ _ ___ ___|_ _|_ __ | |_ ___ _ __ / _| __ _ ___ ___
// | ' /| '_ \ / _ \ \ /\ / / |/ _ \/ _` |/ _` |/ _ \ _ \ / _` / __|/ _ \| || '_ \| __/ _ \ '__| |_ / _` |/ __/ _ \
// | . \| | | | (_) \ V V /| | __/ (_| | (_| | __/ |_) | (_| \__ \ __/| || | | | || __/ | | _| (_| | (_| __/
// |_|\_\_| |_|\___/ \_/\_/ |_|\___|\__,_|\__, |\___|____/ \__,_|___/\___|___|_| |_|\__\___|_| |_| \__,_|\___\___|
// |___/
/// High level interface to the knowledge base
pub trait KnowledgeBaseInterface: KnowledgeBase
{
/// Insert a serializable object
fn insert(
&self,
collection: impl Into<String>,
key: impl Into<String>,
data: &impl serde::Serialize,
) -> Result<()>;
/// Retrieve and deserialize object
fn retrieve<T: serde::de::DeserializeOwned>(
&self,
collection: impl Into<String>,
key: impl Into<String>,
) -> Result<T>;
}
impl<TKnowledgeBase: ?Sized + KnowledgeBase> KnowledgeBaseInterface for TKnowledgeBase
{
/// Insert a serializable object
fn insert(
&self,
collection: impl Into<String>,
key: impl Into<String>,
data: &impl serde::Serialize,
) -> Result<()>
{
let mut data_u8 = Vec::<u8>::new();
ciborium::into_writer(data, &mut data_u8)
.map_err(|e| Error::SerializationError(e.to_string()))?;
self.insert_data(collection.into(), key.into(), data_u8)
}
fn retrieve<T: serde::de::DeserializeOwned>(
&self,
collection: impl Into<String>,
key: impl Into<String>,
) -> Result<T>
{
let data = self.retrieve_data(collection.into(), key.into())?;
Ok(
ciborium::from_reader::<T, &[u8]>(&mut data.as_ref())
.map_err(|e| Error::DeserializationError(e.to_string()))?,
)
}
}
// ___ __ __ ____
// |_ _|_ __ | \/ | ___ _ __ ___ ___ _ __ _ _| __ ) __ _ ___ ___
// | || '_ \| |\/| |/ _ \ '_ ` _ \ / _ \| '__| | | | _ \ / _` / __|/ _ \
// | || | | | | | | __/ | | | | | (_) | | | |_| | |_) | (_| \__ \ __/
// |___|_| |_|_| |_|\___|_| |_| |_|\___/|_| \__, |____/ \__,_|___/\___|
// |___/
/// An implementation of KnowledgeBase where the data is stored in memory
#[derive(Clone)]
pub struct InMemoryBase
{
storage:
utils::ArcMutex<std::collections::HashMap<String, std::collections::HashMap<String, Vec<u8>>>>,
}
impl InMemoryBase
{
/// Create a new in memory database
pub fn new() -> Self
{
Self {
storage: Default::default(),
}
}
}
impl KnowledgeBase for InMemoryBase
{
fn insert_data(&self, collection: String, key: String, data: Vec<u8>) -> Result<()>
{
let mut storage = self.storage.lock()?;
if !storage.contains_key(&collection)
{
storage.insert(collection.clone(), Default::default());
}
if let Some(v) = storage.get_mut(&collection)
{
v.insert(key, data);
return Ok(());
}
else
{
return Err(Error::InvalidCollection(collection));
}
}
fn retrieve_data(&self, collection: String, key: String) -> Result<Vec<u8>>
{
let storage = self.storage.lock()?;
let collection = collection.into();
let key = key.into();
if let Some(v) = storage.get(&collection)
{
if let Some(v) = v.get(&key)
{
return Ok(v.to_owned());
}
}
return Err(Error::UnknownValue(collection, key));
}
}