123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- use crate::core::{Attribute, AttributesData, AttributesRule, Operation};
- use std::{collections::HashMap, fmt};
- #[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
- #[serde(untagged)]
- pub enum Attributes {
- #[serde(skip)]
- Follow,
- Custom(AttributesData),
- #[serde(skip)]
- Empty,
- }
- impl Attributes {
- pub fn data(&self) -> Option<AttributesData> {
- match self {
- Attributes::Follow => None,
- Attributes::Custom(data) => Some(data.clone()),
- Attributes::Empty => None,
- }
- }
- pub fn is_empty(&self) -> bool {
- match self {
- Attributes::Follow => true,
- Attributes::Custom(data) => data.is_empty(),
- Attributes::Empty => true,
- }
- }
- }
- impl std::default::Default for Attributes {
- fn default() -> Self { Attributes::Empty }
- }
- impl fmt::Display for Attributes {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Attributes::Follow => {
- f.write_str("")?;
- },
- Attributes::Custom(data) => {
- f.write_fmt(format_args!("{:?}", data.inner))?;
- },
- Attributes::Empty => {
- f.write_str("")?;
- },
- }
- Ok(())
- }
- }
- pub(crate) fn attributes_from(operation: &Option<Operation>) -> Option<Attributes> {
- match operation {
- None => None,
- Some(operation) => Some(operation.get_attributes()),
- }
- }
- pub fn compose_operation(left: &Option<Operation>, right: &Option<Operation>) -> Attributes {
- if left.is_none() && right.is_none() {
- return Attributes::Empty;
- }
- let attr_l = attributes_from(left);
- let attr_r = attributes_from(right);
- if attr_l.is_none() {
- return attr_r.unwrap();
- }
- if attr_r.is_none() {
- return attr_l.unwrap();
- }
- compose_attributes(attr_l.unwrap(), attr_r.unwrap())
- }
- pub fn transform_operation(left: &Option<Operation>, right: &Option<Operation>) -> Attributes {
- let attr_l = attributes_from(left);
- let attr_r = attributes_from(right);
- if attr_l.is_none() {
- if attr_r.is_none() {
- return Attributes::Empty;
- }
- return match attr_r.as_ref().unwrap() {
- Attributes::Follow => Attributes::Follow,
- Attributes::Custom(_) => attr_r.unwrap(),
- Attributes::Empty => Attributes::Empty,
- };
- }
- transform_attributes(attr_l.unwrap(), attr_r.unwrap())
- }
- pub fn invert_attributes(attr: Attributes, base: Attributes) -> Attributes {
- log::info!("Invert attributes: {:?} : {:?}", attr, base);
- let attr = attr.data();
- let base = base.data();
- if attr.is_none() && base.is_none() {
- return Attributes::Empty;
- }
- let attr = attr.unwrap_or(AttributesData::new());
- let base = base.unwrap_or(AttributesData::new());
- let base_inverted = base
- .iter()
- .fold(AttributesData::new(), |mut attributes, (k, v)| {
- if base.get(k) != attr.get(k) && attr.contains_key(k) {
- attributes.insert(k.clone(), v.clone());
- }
- attributes
- });
- let inverted = attr.iter().fold(base_inverted, |mut attributes, (k, _)| {
- if base.get(k) != attr.get(k) && !base.contains_key(k) {
- attributes.remove(k);
- }
- attributes
- });
- return Attributes::Custom(inverted);
- }
- pub fn merge_attributes(attributes: Attributes, other: Attributes) -> Attributes {
- match (&attributes, &other) {
- (Attributes::Custom(data), Attributes::Custom(o_data)) => {
- let mut data = data.clone();
- data.extend(Some(o_data.clone()), false);
- Attributes::Custom(data)
- },
- (Attributes::Custom(data), _) => Attributes::Custom(data.clone()),
- _ => other,
- }
- }
- fn compose_attributes(left: Attributes, right: Attributes) -> Attributes {
- log::trace!("compose_attributes: a: {:?}, b: {:?}", left, right);
- let attr = match (&left, &right) {
- (_, Attributes::Empty) => Attributes::Empty,
- (_, Attributes::Custom(_)) => merge_attributes(left, right),
- (Attributes::Custom(_), _) => merge_attributes(left, right),
- _ => Attributes::Follow,
- };
- log::trace!("composed_attributes: a: {:?}", attr);
- attr.apply_rule()
- }
- fn transform_attributes(left: Attributes, right: Attributes) -> Attributes {
- match (left, right) {
- (Attributes::Custom(data_l), Attributes::Custom(data_r)) => {
- let result = data_r
- .iter()
- .fold(AttributesData::new(), |mut new_attr_data, (k, v)| {
- if !data_l.contains_key(k) {
- new_attr_data.insert(k.clone(), v.clone());
- }
- new_attr_data
- });
- Attributes::Custom(result)
- },
- _ => Attributes::Empty,
- }
- }
|