summaryrefslogtreecommitdiff
path: root/plugins/warp/src/container/memory.rs
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/warp/src/container/memory.rs')
-rw-r--r--plugins/warp/src/container/memory.rs307
1 files changed, 307 insertions, 0 deletions
diff --git a/plugins/warp/src/container/memory.rs b/plugins/warp/src/container/memory.rs
new file mode 100644
index 00000000..cf53390e
--- /dev/null
+++ b/plugins/warp/src/container/memory.rs
@@ -0,0 +1,307 @@
+use crate::container::{Container, ContainerError, ContainerResult, SourceId, SourcePath};
+use std::collections::HashMap;
+use std::fmt::Display;
+use warp::r#type::guid::TypeGUID;
+use warp::r#type::{ComputedType, Type};
+use warp::signature::function::{Function, FunctionGUID};
+use warp::target::Target;
+
+#[derive(Debug, Clone, PartialEq, Eq, Default)]
+pub struct MemoryContainer {
+ sources: HashMap<SourceId, MemorySource>,
+}
+
+impl MemoryContainer {
+ pub fn new() -> Self {
+ MemoryContainer::default()
+ }
+
+ pub fn with_source(mut self, id: SourceId, source: MemorySource) -> Self {
+ self.sources.insert(id, source);
+ self
+ }
+
+ pub fn with_source_function(
+ mut self,
+ id: SourceId,
+ guid: FunctionGUID,
+ func: Function,
+ ) -> Self {
+ self.sources
+ .entry(id)
+ .or_default()
+ .functions
+ .entry(guid)
+ .or_default()
+ .push(func);
+ self
+ }
+
+ pub fn with_source_type(mut self, id: SourceId, guid: TypeGUID, ty: Type) -> Self {
+ self.sources.entry(id).or_default().types.insert(guid, ty);
+ self
+ }
+}
+
+impl Container for MemoryContainer {
+ fn sources(&self) -> ContainerResult<Vec<SourceId>> {
+ todo!()
+ }
+
+ fn add_source(&mut self, path: SourcePath) -> ContainerResult<SourceId> {
+ Err(ContainerError::CannotCreateSource(path))
+ }
+
+ fn commit_source(&mut self, _source: &SourceId) -> ContainerResult<bool> {
+ Ok(false)
+ }
+
+ fn is_source_writable(&self, source: &SourceId) -> ContainerResult<bool> {
+ let memory_source = self
+ .sources
+ .get(source)
+ .ok_or(ContainerError::SourceNotFound(*source))?;
+ Ok(memory_source.writable)
+ }
+
+ fn is_source_uncommitted(&self, source: &SourceId) -> ContainerResult<bool> {
+ let _memory_source = self
+ .sources
+ .get(source)
+ .ok_or(ContainerError::SourceNotFound(*source))?;
+ // NOTE: Memory containers do not have a notion of uncommitted data.
+ Ok(false)
+ }
+
+ fn source_path(&self, source: &SourceId) -> ContainerResult<SourcePath> {
+ Err(ContainerError::SourcePathUnavailable(*source))
+ }
+
+ fn add_computed_types(
+ &mut self,
+ source: &SourceId,
+ types: &[ComputedType],
+ ) -> ContainerResult<()> {
+ let memory_source = self
+ .sources
+ .get_mut(source)
+ .ok_or(ContainerError::SourceNotFound(*source))?;
+ match memory_source.writable {
+ true => {
+ for ty in types {
+ memory_source.types.insert(ty.guid, ty.ty.clone());
+ }
+ Ok(())
+ }
+ false => Err(ContainerError::SourceNotWritable(*source)),
+ }
+ }
+
+ fn remove_types(&mut self, source: &SourceId, guids: &[TypeGUID]) -> ContainerResult<()> {
+ let memory_source = self
+ .sources
+ .get_mut(source)
+ .ok_or(ContainerError::SourceNotFound(*source))?;
+ match memory_source.writable {
+ true => {
+ for guid in guids {
+ memory_source.types.remove(guid);
+ }
+ Ok(())
+ }
+ false => Err(ContainerError::SourceNotWritable(*source)),
+ }
+ }
+
+ fn add_functions(
+ &mut self,
+ _target: &Target,
+ source: &SourceId,
+ functions: &[Function],
+ ) -> ContainerResult<()> {
+ let memory_source = self
+ .sources
+ .get_mut(source)
+ .ok_or(ContainerError::SourceNotFound(*source))?;
+ match memory_source.writable {
+ true => {
+ for function in functions {
+ memory_source
+ .functions
+ .entry(function.guid)
+ .or_default()
+ .push(function.clone());
+ }
+ Ok(())
+ }
+ false => Err(ContainerError::SourceNotWritable(*source)),
+ }
+ }
+
+ fn remove_functions(
+ &mut self,
+ _target: &Target,
+ source: &SourceId,
+ functions: &[Function],
+ ) -> ContainerResult<()> {
+ let memory_source = self
+ .sources
+ .get_mut(source)
+ .ok_or(ContainerError::SourceNotFound(*source))?;
+ match memory_source.writable {
+ true => {
+ for function in functions {
+ if let Some(src_funcs) = memory_source.functions.get_mut(&function.guid) {
+ src_funcs.retain(|f| f != function);
+ if src_funcs.is_empty() {
+ memory_source.functions.remove(&function.guid);
+ }
+ }
+ }
+ Ok(())
+ }
+ false => Err(ContainerError::SourceNotWritable(*source)),
+ }
+ }
+
+ fn sources_with_type_guid(&self, guid: &TypeGUID) -> ContainerResult<Vec<SourceId>> {
+ let sources = self
+ .sources
+ .iter()
+ .filter(|(_, source)| source.has_type_with_guid(guid))
+ .map(|(id, _)| *id)
+ .collect();
+ Ok(sources)
+ }
+
+ fn sources_with_type_guids(
+ &self,
+ guids: &[TypeGUID],
+ ) -> ContainerResult<HashMap<TypeGUID, Vec<SourceId>>> {
+ let mut result: HashMap<TypeGUID, Vec<SourceId>> = HashMap::new();
+ for (source_id, source) in &self.sources {
+ guids
+ .iter()
+ .filter(|guid| source.has_type_with_guid(guid))
+ .for_each(|guid| result.entry(*guid).or_default().push(*source_id));
+ }
+ Ok(result)
+ }
+
+ fn type_guids_with_name(
+ &self,
+ source: &SourceId,
+ name: &str,
+ ) -> ContainerResult<Vec<TypeGUID>> {
+ let memory_source = self
+ .sources
+ .get(source)
+ .ok_or(ContainerError::SourceNotFound(*source))?;
+ Ok(memory_source.type_guids_with_name(name))
+ }
+
+ fn type_with_guid(&self, source: &SourceId, guid: &TypeGUID) -> ContainerResult<Option<Type>> {
+ let memory_source = self
+ .sources
+ .get(source)
+ .ok_or(ContainerError::SourceNotFound(*source))?;
+ Ok(memory_source.type_with_guid(guid))
+ }
+
+ fn sources_with_function_guid(
+ &self,
+ _target: &Target,
+ guid: &FunctionGUID,
+ ) -> ContainerResult<Vec<SourceId>> {
+ let sources = self
+ .sources
+ .iter()
+ .filter(|(_, source)| source.has_function_with_guid(guid))
+ .map(|(id, _)| *id)
+ .collect();
+ Ok(sources)
+ }
+
+ fn sources_with_function_guids(
+ &self,
+ _target: &Target,
+ guids: &[FunctionGUID],
+ ) -> ContainerResult<HashMap<FunctionGUID, Vec<SourceId>>> {
+ let mut result: HashMap<FunctionGUID, Vec<SourceId>> = HashMap::new();
+ for (source_id, source) in &self.sources {
+ guids
+ .iter()
+ .filter(|guid| source.has_function_with_guid(guid))
+ .for_each(|guid| result.entry(*guid).or_default().push(*source_id));
+ }
+ Ok(result)
+ }
+
+ fn functions_with_guid(
+ &self,
+ _target: &Target,
+ source: &SourceId,
+ guid: &FunctionGUID,
+ ) -> ContainerResult<Vec<Function>> {
+ let memory_source = self
+ .sources
+ .get(source)
+ .ok_or(ContainerError::SourceNotFound(*source))?;
+ Ok(memory_source.functions_with_guid(guid))
+ }
+}
+
+impl Display for MemoryContainer {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str("MemoryContainer")
+ }
+}
+
+/// An in-memory store of functions.
+///
+/// This is typically an overlay on top of a container source.
+#[derive(Eq, PartialEq, Debug, Clone)]
+pub struct MemorySource {
+ pub writable: bool,
+ pub functions: HashMap<FunctionGUID, Vec<Function>>,
+ pub types: HashMap<TypeGUID, Type>,
+ pub named_types: HashMap<String, Vec<TypeGUID>>,
+}
+
+impl MemorySource {
+ pub fn type_guids_with_name(&self, name: &str) -> Vec<TypeGUID> {
+ // TODO: The function here is a little goofy.
+ // TODO: This is cloned.
+ self.named_types.get(name).cloned().unwrap_or_default()
+ }
+
+ pub fn type_with_guid(&self, guid: &TypeGUID) -> Option<Type> {
+ // TODO: This is cloned.
+ self.types.get(guid).cloned()
+ }
+
+ pub fn functions_with_guid(&self, guid: &FunctionGUID) -> Vec<Function> {
+ // TODO: The function here is a little goofy.
+ // TODO: This is cloned.
+ self.functions.get(guid).cloned().unwrap_or_default()
+ }
+
+ pub fn has_type_with_guid(&self, guid: &TypeGUID) -> bool {
+ self.type_with_guid(guid).is_some()
+ }
+
+ pub fn has_function_with_guid(&self, guid: &FunctionGUID) -> bool {
+ !self.functions_with_guid(guid).is_empty()
+ }
+}
+
+impl Default for MemorySource {
+ fn default() -> Self {
+ Self {
+ writable: true,
+ functions: HashMap::new(),
+ types: HashMap::new(),
+ named_types: HashMap::new(),
+ }
+ }
+}