Skip to content

Commit

Permalink
feat: add Link overlay
Browse files Browse the repository at this point in the history
  • Loading branch information
olichwiruk committed Dec 30, 2024
1 parent 328f72f commit 5d66242
Show file tree
Hide file tree
Showing 11 changed files with 264 additions and 1 deletion.
29 changes: 28 additions & 1 deletion oca/src/local_references.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use std::str::FromStr;

use oca_ast_semantics::ast::{CommandType, NestedAttrType, OCAAst, ObjectKind, RefValue};
use oca_ast_semantics::ast::{
CommandType, NestedAttrType, NestedValue, OCAAst, ObjectKind, OverlayType,
RefValue,
};
use said::SelfAddressingIdentifier;

use crate::facade::build::ValidationError;
Expand Down Expand Up @@ -48,6 +51,30 @@ pub fn replace_refn_with_refs<R: References>(
}
}
}

if let (
CommandType::Add,
ObjectKind::Overlay(OverlayType::Link, content),
) = (&command.kind, &mut command.object_kind)
{
if let Some(properties) = &mut content.properties {
if let Some(NestedValue::Reference(RefValue::Name(refn))) =
properties.get("target")
{
if let Some(said) = references.find(refn) {
let said =
SelfAddressingIdentifier::from_str(&said).unwrap(); // todo
properties.insert(
"target".to_string(),
NestedValue::Reference(RefValue::Said(said)),
);
*properties = properties.clone();
} else {
return Err(ValidationError::UnknownRefn(refn.clone()));
}
}
}
}
}
Ok(())
}
20 changes: 20 additions & 0 deletions semantics/oca-ast/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ pub enum OverlayType {
UnitMapping,
Layout,
Sensitivity,
Link,
}

impl Serialize for OverlayType {
Expand Down Expand Up @@ -186,6 +187,7 @@ impl Serialize for OverlayType {
OverlayType::UnitMapping => serializer.serialize_str("spec/overlays/unit_mapping/1.0"),
OverlayType::Layout => serializer.serialize_str("spec/overlays/layout/1.0"),
OverlayType::Sensitivity => serializer.serialize_str("spec/overlays/sensitivity/1.0"),
OverlayType::Link => serializer.serialize_str("spec/overlays/link/1.0"),
}
}
}
Expand Down Expand Up @@ -240,6 +242,7 @@ impl FromStr for OverlayType {
"UnitMapping" => Ok(OverlayType::UnitMapping),
"Layout" => Ok(OverlayType::Layout),
"Sensitivity" => Ok(OverlayType::Sensitivity),
"Link" => Ok(OverlayType::Link),
_ => Err(()),
}
}
Expand Down Expand Up @@ -267,6 +270,7 @@ impl fmt::Display for OverlayType {
OverlayType::UnitMapping => write!(f, "UnitMapping"),
OverlayType::Layout => write!(f, "Layout"),
OverlayType::Sensitivity => write!(f, "Sensitivity"),
OverlayType::Link => write!(f, "Link"),
}
}
}
Expand Down Expand Up @@ -297,6 +301,7 @@ impl<'de> Deserialize<'de> for OverlayType {
"spec/overlays/unit_mapping/1.0" => Ok(OverlayType::UnitMapping),
"spec/overlays/layout/1.0" => Ok(OverlayType::Layout),
"spec/overlays/sensitivity/1.0" => Ok(OverlayType::Sensitivity),
"spec/overlays/link/1.0" => Ok(OverlayType::Link),
_ => Err(serde::de::Error::custom(format!(
"unknown overlay type: {}",
s
Expand Down Expand Up @@ -759,6 +764,13 @@ impl From<u8> for ObjectKind {
properties: None,
},
),
21 => ObjectKind::Overlay(
OverlayType::Link,
Content {
attributes: None,
properties: None,
},
),
_ => panic!("Unknown object type"),
}
}
Expand Down Expand Up @@ -788,6 +800,7 @@ impl From<ObjectKind> for u8 {
ObjectKind::Overlay(OverlayType::UnitMapping, _) => 18,
ObjectKind::Overlay(OverlayType::Layout, _) => 19,
ObjectKind::Overlay(OverlayType::Sensitivity, _) => 20,
ObjectKind::Overlay(OverlayType::Link, _) => 21,
}
}
}
Expand Down Expand Up @@ -940,6 +953,13 @@ impl<'de> Deserialize<'de> for ObjectKind {
properties: None,
},
)),
"Link" => Ok(ObjectKind::Overlay(
OverlayType::Link,
Content {
attributes: None,
properties: None,
},
)),
_ => Err(serde::de::Error::custom(format!(
"unknown object kind: {}",
s
Expand Down
29 changes: 29 additions & 0 deletions semantics/oca-bundle/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::state::oca::overlay::information::Information;
use crate::state::oca::overlay::label::Labels;
use crate::state::oca::overlay::meta::Metas;
use crate::state::oca::overlay::unit::Units;
use crate::state::oca::overlay::link::Links;
use crate::state::oca::OCABundle;
use crate::state::{
attribute::Attribute, encoding::Encoding, entries::EntriesElement,
Expand Down Expand Up @@ -442,6 +443,34 @@ pub fn apply_command(base: Option<OCABox>, op: ast::Command) -> Result<OCABox, V
}
}
}
ast::OverlayType::Link => {
let mut target_bundle = None;
if let Some(ref properties) = content.properties {
if let Some(ast::NestedValue::Reference(ast::RefValue::Said(target_said))) = properties.get("target") {
target_bundle = Some(target_said.to_string());
}
}
if target_bundle.is_none() {
errors.push("Undefined target bundle".to_string());
}

if let Some(ref attributes) = content.attributes {
for (attr_name, attr_type_value) in attributes {
let mut attribute = oca
.attributes
.get(attr_name)
.ok_or_else(|| {
errors.push(format!("Undefined attribute: {attr_name}"));
errors.clone()
})?
.clone();
if let ast::NestedValue::Value(linked_attr) = attr_type_value {
attribute.set_link(target_bundle.clone().unwrap(), linked_attr.clone());
}
oca.add_attribute(attribute);
}
}
}
_ => (),
}
}
Expand Down
6 changes: 6 additions & 0 deletions semantics/oca-bundle/src/state/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub struct Attribute {
pub cardinality: Option<String>,
pub conformance: Option<String>,
pub standards: Option<Vec<Standard>>,
pub links: Option<HashMap<String, String>>,
}

impl Default for Attribute {
Expand Down Expand Up @@ -58,6 +59,7 @@ impl Attribute {
cardinality: None,
conformance: None,
standards: None,
links: None,
}
}

Expand Down Expand Up @@ -128,6 +130,10 @@ impl Attribute {
if other.standards.is_some() {
self.standards.clone_from(&other.standards);
}

if other.links.is_some() {
self.links.clone_from(&other.links);
}
}
}

Expand Down
30 changes: 30 additions & 0 deletions semantics/oca-bundle/src/state/oca.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,26 @@ impl OCABox {
}
}
}

if let Some(links) = &attribute.links {
for target_bundle in links.keys() {
let mut link_ov = overlays.iter_mut().find(|x| {
match x.as_any().downcast_ref::<overlay::Link>() {
Some(o) => o.target_bundle == *target_bundle,
None => false,
}
});

if link_ov.is_none() {
overlays
.push(Box::new(overlay::Link::new(target_bundle.clone())));
link_ov = overlays.last_mut();
}
if let Some(ov) = link_ov {
ov.add(attribute);
}
}
}
}

overlays
Expand Down Expand Up @@ -474,6 +494,15 @@ impl<'de> Deserialize<'de> for DynOverlay {
})?,
));
}
OverlayType::Link => {
return Ok(Box::new(
de_overlay
.deserialize_into::<overlay::Link>()
.map_err(|e| {
serde::de::Error::custom(format!("Link overlay: {e}"))
})?,
));
}
_ => {
return Err(serde::de::Error::custom(format!(
"Overlay type not supported: {:?}",
Expand Down Expand Up @@ -511,6 +540,7 @@ where
OverlayType::Entry,
OverlayType::Label,
OverlayType::Information,
OverlayType::Link,
];

let mut overlays_map: BTreeMap<Value, OverlayValue> = BTreeMap::new();
Expand Down
2 changes: 2 additions & 0 deletions semantics/oca-bundle/src/state/oca/overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod meta;
pub mod standard;
pub mod subset;
pub mod unit;
pub mod link;

pub use self::attribute_mapping::AttributeMappingOverlay as AttributeMapping;
pub use self::cardinality::CardinalityOverlay as Cardinality;
Expand All @@ -30,6 +31,7 @@ pub use self::label::LabelOverlay as Label;
pub use self::meta::MetaOverlay as Meta;
pub use self::standard::StandardOverlay as Standard;
pub use self::subset::SubsetOverlay as Subset;
pub use self::link::LinkOverlay as Link;
pub use oca_ast_semantics::ast::OverlayType;
use said::derivation::HashFunctionCode;

Expand Down
94 changes: 94 additions & 0 deletions semantics/oca-bundle/src/state/oca/overlay/link.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use crate::state::{attribute::Attribute, oca::Overlay};
use oca_ast_semantics::ast::OverlayType;
use said::derivation::HashFunctionCode;
use said::{sad::SerializationFormats, sad::SAD};
use serde::{ser::SerializeMap, Deserialize, Serialize, Serializer};
use std::any::Any;
use std::collections::HashMap;

pub trait Links {
fn set_link(&mut self, t: String, link: String);
}

impl Links for Attribute {
fn set_link(&mut self, t: String, link: String) {
if let Some(links) = &mut self.links {
links.insert(t, link);
} else {
let mut links = HashMap::new();
links.insert(t, link);
self.links = Some(links);
}
}
}

pub fn serialize_attributes<S>(
attributes: &HashMap<String, String>,
s: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use std::collections::BTreeMap;

let mut ser = s.serialize_map(Some(attributes.len()))?;
let sorted_attributes: BTreeMap<_, _> = attributes.iter().collect();
for (k, v) in sorted_attributes {
ser.serialize_entry(k, v)?;
}
ser.end()
}

#[derive(SAD, Serialize, Deserialize, Debug, Clone)]
pub struct LinkOverlay {
#[said]
#[serde(rename = "d")]
said: Option<said::SelfAddressingIdentifier>,
capture_base: Option<said::SelfAddressingIdentifier>,
#[serde(rename = "type")]
overlay_type: OverlayType,
pub target_bundle: String,
#[serde(serialize_with = "serialize_attributes")]
pub attribute_mapping: HashMap<String, String>,
}

impl Overlay for LinkOverlay {
fn as_any(&self) -> &dyn Any {
self
}
fn capture_base(&self) -> &Option<said::SelfAddressingIdentifier> {
&self.capture_base
}
fn set_capture_base(&mut self, said: &said::SelfAddressingIdentifier) {
self.capture_base = Some(said.clone());
}
fn overlay_type(&self) -> &OverlayType {
&self.overlay_type
}
fn said(&self) -> &Option<said::SelfAddressingIdentifier> {
&self.said
}
fn attributes(&self) -> Vec<&String> {
self.attribute_mapping.keys().collect::<Vec<&String>>()
}

fn add(&mut self, attribute: &Attribute) {
if let Some(links) = &attribute.links {
if let Some(value) = links.get(&self.target_bundle) {
self.attribute_mapping
.insert(attribute.name.clone(), value.to_string());
}
}
}
}
impl LinkOverlay {
pub fn new(t: String) -> Self {
Self {
capture_base: None,
said: None,
overlay_type: OverlayType::Link,
target_bundle: t,
attribute_mapping: HashMap::new(),
}
}
}
3 changes: 3 additions & 0 deletions semantics/oca-file/src/ocafile.pest
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ oca_object = _{
cardinality |
entry_code |
entry |
link |
flagged_attrs
)
}
Expand All @@ -151,6 +152,7 @@ remove_oca_object = _{
cardinality |
entry_code |
entry |
link |
flagged_attrs
)
}
Expand All @@ -169,6 +171,7 @@ cardinality = {^"cardinality" ~ arg_ws ~ attrs_key ~ attr_key_pairs}
entry_code = {^"entry_code" ~ arg_ws ~ attrs_key ~ attr_entry_code_key_pairs}
entry = {^"entry" ~ arg_ws ~ lang ~ arg_ws ~ attrs_key ~ attr_entry_key_pairs}
unit = {^"unit" ~ arg_ws ~ attrs_key ~ attr_key_pairs}
link = {^"link" ~ arg_ws ~ reference_type ~ arg_ws ~ attrs_key ~ attr_key_pairs}

flagged_attrs = {^"flagged_attributes" ~ arg_ws ~ list_value}
classification = { ^"classification" ~ arg_ws ~ classification_value}
Expand Down
6 changes: 6 additions & 0 deletions semantics/oca-file/src/ocafile/instructions/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ impl AddInstruction {
helpers::extract_content(object),
));
}
Rule::link => {
object_kind = Some(ObjectKind::Overlay(
OverlayType::Link,
helpers::extract_content(object),
));
}
Rule::flagged_attrs => {
object_kind = Some(ObjectKind::CaptureBase(CaptureContent {
properties: None,
Expand Down
Loading

0 comments on commit 5d66242

Please sign in to comment.