blob: fb05237ad3dd3561d59e15ea0ce21d52bbf5d17a [file] [log] [blame]
/*********************************************************************
* Copyright (c) 2024 Boeing
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Boeing - initial API and implementation
**********************************************************************/
use crate::{
applicability_parser_syntax_tag::{
SubstitutionSyntaxTag, SubstitutionSyntaxTagAnd, SubstitutionSyntaxTagOr,
},
ApplicabilityParserSyntaxTag,
};
use std::str::FromStr;
pub trait SubstituteApplicability {
fn substitute(&self, substitutes: &[Substitution]) -> ApplicabilityParserSyntaxTag;
}
#[derive(Debug, Clone, Default)]
pub struct Substitution {
pub match_text: String,
pub substitute: String,
}
impl FromStr for Substitution {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let split = s.split_once('=');
match split {
Some((matching_text, substitution_text)) => Ok(Self {
match_text: matching_text.to_string(),
substitute: substitution_text.to_string(),
}),
None => Ok(Self::default()),
}
}
}
#[cfg(feature = "serde")]
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct SubstitutionInner {
pub match_text: String,
pub substitute: String,
}
#[cfg(feature = "serde")]
impl From<SubstitutionInner> for Substitution {
fn from(value: SubstitutionInner) -> Self {
Self {
match_text: value.match_text,
substitute: value.substitute,
}
}
}
#[cfg(feature = "serde")]
use serde::{de::Error, Deserialize};
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Substitution {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(untagged)]
enum SubstitutionVariants {
StringSub(String),
SubstitutionElement(SubstitutionInner),
}
match SubstitutionVariants::deserialize(deserializer) {
Ok(result) => match result {
SubstitutionVariants::StringSub(str) => match str.split_once('=') {
Some((match_text, substitution_text)) => Ok(Self {
match_text: match_text.to_string(),
substitute: substitution_text.to_string(),
}),
None => Ok(Self {
match_text: str,
substitute: "".to_string(),
}),
},
SubstitutionVariants::SubstitutionElement(sub) => Ok(sub.into()),
},
Err(deserializer_error) => Err(D::Error::custom(deserializer_error.to_string())),
}
}
}
impl SubstituteApplicability for ApplicabilityParserSyntaxTag {
fn substitute(&self, substitutes: &[Substitution]) -> ApplicabilityParserSyntaxTag {
match self {
ApplicabilityParserSyntaxTag::Text(_)
| ApplicabilityParserSyntaxTag::Tag(_)
| ApplicabilityParserSyntaxTag::TagAnd(_)
| ApplicabilityParserSyntaxTag::TagOr(_)
| ApplicabilityParserSyntaxTag::TagNot(_)
| ApplicabilityParserSyntaxTag::TagNotAnd(_)
| ApplicabilityParserSyntaxTag::TagNotOr(_) => self.clone(),
ApplicabilityParserSyntaxTag::Substitution(t) => t.substitute(substitutes),
ApplicabilityParserSyntaxTag::SubstitutionOr(t) => t.substitute(substitutes),
ApplicabilityParserSyntaxTag::SubstitutionAnd(t) => t.substitute(substitutes),
//intentionally not implemented, future growth if needed, these paths don't exist yet.
ApplicabilityParserSyntaxTag::SubstitutionNot(_) => todo!(),
ApplicabilityParserSyntaxTag::SubstitutionNotAnd(_) => todo!(),
ApplicabilityParserSyntaxTag::SubstitutionNotOr(_) => todo!(),
}
}
}
impl SubstituteApplicability for SubstitutionSyntaxTag {
fn substitute(&self, substitutes: &[Substitution]) -> ApplicabilityParserSyntaxTag {
//look for the substitutes in the array and return the matching ElementType::Text
match substitutes
.iter()
.filter(|&substitution| &substitution.match_text == self)
.cloned()
.map(|substitution_syntax_tag| {
ApplicabilityParserSyntaxTag::Text(substitution_syntax_tag.substitute)
})
.last()
{
Some(elem) => elem,
None => ApplicabilityParserSyntaxTag::Text("".to_string()),
}
}
}
impl SubstituteApplicability for SubstitutionSyntaxTagOr {
fn substitute(&self, substitutes: &[Substitution]) -> ApplicabilityParserSyntaxTag {
match substitutes
.iter()
.filter(|&substitution| self.0.contains(&substitution.match_text))
.cloned()
.map(|substitution_syntax_tag| {
ApplicabilityParserSyntaxTag::Text(substitution_syntax_tag.substitute)
})
.last()
{
Some(elem) => elem,
None => ApplicabilityParserSyntaxTag::Text("".to_string()),
}
}
}
impl SubstituteApplicability for SubstitutionSyntaxTagAnd {
fn substitute(&self, substitutes: &[Substitution]) -> ApplicabilityParserSyntaxTag {
let count = substitutes
.iter()
.filter(|&substitution| self.0.contains(&substitution.match_text))
.cloned()
.count();
match count == self.0.len() {
true => match substitutes
.iter()
.filter(|&substitution| self.0.contains(&substitution.match_text))
.cloned()
.map(|substitution_syntax_tag| {
ApplicabilityParserSyntaxTag::Text(substitution_syntax_tag.substitute)
})
.last()
{
Some(elem) => elem,
None => ApplicabilityParserSyntaxTag::Text("".to_string()),
},
false => ApplicabilityParserSyntaxTag::Text("".to_string()),
}
}
}