use crate::error::{Error, ErrorKind};
use crate::model::values::Number;
use crate::model::{Identifier, ShapeID};
use std::fmt::{Display, Formatter};
use std::str::FromStr;
#[derive(Clone, Debug, PartialEq)]
pub enum ShapeType {
Any,
Number,
SimpleType,
Collection,
Blob,
Boolean,
Document,
String,
Integer,
Byte,
Short,
Long,
Float,
Double,
BigDecimal,
BigInteger,
Timestamp,
List,
Set,
Map,
Structure,
Union,
Service,
Operation,
Resource,
Member,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Text(String),
Number(Number),
RootShapeIdentifier(Identifier),
AbsoluteRootShapeIdentifier(ShapeID),
}
#[derive(Clone, Debug, PartialEq)]
pub enum KeyPathSegment {
Value(Value),
FunctionProperty(Identifier),
}
#[derive(Clone, Debug, PartialEq)]
pub struct Key {
identifier: Identifier,
path: Vec<KeyPathSegment>,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Comparator {
StringEqual,
StringNotEqual,
StringStartsWith,
StringEndsWith,
StringContains,
StringExists,
NumberGreaterThan,
NumberGreaterOrEqual,
NumberLessThan,
NumberLessOrEqual,
ProjectionEqual,
ProjectionNotEqual,
ProjectionSubset,
ProjectionProperSubset,
}
#[derive(Clone, Debug, PartialEq)]
pub struct AttributeComparison {
comparator: Comparator,
rhs_values: Vec<Value>,
case_insensitive: bool,
}
#[derive(Clone, Debug, PartialEq)]
pub struct AttributeSelector {
key: Key,
comparison: Option<AttributeComparison>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct ScopedAttributeSelector {
key: Option<Key>,
assertions: Vec<ScopedAttributeAssertion>,
}
#[derive(Clone, Debug, PartialEq)]
pub enum ScopedValue {
Value(Value),
ContextValue(Vec<KeyPathSegment>),
}
#[derive(Clone, Debug, PartialEq)]
pub struct ScopedAttributeAssertion {
lhs_value: ScopedValue,
comparator: Comparator,
rhs_values: Vec<ScopedValue>,
case_insensitive: bool,
}
#[derive(Clone, Debug, PartialEq)]
pub enum NeighborSelector {
ForwardUndirected,
ReverseUndirected,
ForwardDirected(Vec<Identifier>),
ReverseDirected(Vec<Identifier>),
ForwardRecursiveDirected,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Function {
name: Identifier,
arguments: Vec<Selector>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct VariableDefinition {
name: Identifier,
selector: Selector,
}
#[derive(Clone, Debug, PartialEq)]
pub struct VariableReference {
name: Identifier,
}
#[derive(Clone, Debug, PartialEq)]
pub enum SelectorExpression {
ShapeType(ShapeType),
AttributeSelector(AttributeSelector),
ScopedAttributeSelector(ScopedAttributeSelector),
NeighborSelector(NeighborSelector),
Function(Function),
VariableDefinition(VariableDefinition),
VariableReference(VariableReference),
}
#[derive(Clone, Debug, PartialEq)]
pub struct Selector {
expressions: Vec<SelectorExpression>,
}
impl Display for ShapeType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
ShapeType::Any => "*",
ShapeType::Number => "number",
ShapeType::SimpleType => "simpleType",
ShapeType::Collection => "collection",
ShapeType::Blob => "blob",
ShapeType::Boolean => "boolean",
ShapeType::Document => "document",
ShapeType::String => "string",
ShapeType::Integer => "integer",
ShapeType::Byte => "byte",
ShapeType::Short => "short",
ShapeType::Long => "long",
ShapeType::Float => "float",
ShapeType::Double => "double",
ShapeType::BigDecimal => "bigDecimal",
ShapeType::BigInteger => "bigInteger",
ShapeType::Timestamp => "timestamp",
ShapeType::List => "list",
ShapeType::Set => "set",
ShapeType::Map => "map",
ShapeType::Structure => "structure",
ShapeType::Union => "union",
ShapeType::Service => "service",
ShapeType::Operation => "operation",
ShapeType::Resource => "resource",
ShapeType::Member => "member",
}
)
}
}
impl FromStr for ShapeType {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"*" => Ok(ShapeType::Any),
"number" => Ok(ShapeType::Number),
"simpleType" => Ok(ShapeType::SimpleType),
"collection" => Ok(ShapeType::Collection),
"blob" => Ok(ShapeType::Blob),
"boolean" => Ok(ShapeType::Boolean),
"document" => Ok(ShapeType::Document),
"string" => Ok(ShapeType::String),
"integer" => Ok(ShapeType::Integer),
"byte" => Ok(ShapeType::Byte),
"short" => Ok(ShapeType::Short),
"long" => Ok(ShapeType::Long),
"float" => Ok(ShapeType::Float),
"double" => Ok(ShapeType::Double),
"bigDecimal" => Ok(ShapeType::BigDecimal),
"bigInteger" => Ok(ShapeType::BigInteger),
"timestamp" => Ok(ShapeType::Timestamp),
"list" => Ok(ShapeType::List),
"set" => Ok(ShapeType::Set),
"map" => Ok(ShapeType::Map),
"structure" => Ok(ShapeType::Structure),
"union" => Ok(ShapeType::Union),
"service" => Ok(ShapeType::Service),
"operation" => Ok(ShapeType::Operation),
"resource" => Ok(ShapeType::Resource),
"member" => Ok(ShapeType::Member),
_ => Err(ErrorKind::InvalidSelectorExpression(s.to_string()).into()),
}
}
}
impl From<ShapeType> for SelectorExpression {
fn from(v: ShapeType) -> Self {
SelectorExpression::ShapeType(v)
}
}
impl Display for Value {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Value::Text(v) => format!("\"{}\"", v),
Value::Number(v) => v.to_string(),
Value::RootShapeIdentifier(v) => v.to_string(),
Value::AbsoluteRootShapeIdentifier(v) => v.to_string(),
}
)
}
}
impl From<String> for Value {
fn from(v: String) -> Self {
Value::Text(v)
}
}
impl From<&str> for Value {
fn from(v: &str) -> Self {
Value::Text(v.to_string())
}
}
impl From<Number> for Value {
fn from(v: Number) -> Self {
Value::Number(v)
}
}
impl From<i64> for Value {
fn from(v: i64) -> Self {
Value::Number(v.into())
}
}
impl From<f64> for Value {
fn from(v: f64) -> Self {
Value::Number(v.into())
}
}
impl From<Identifier> for Value {
fn from(v: Identifier) -> Self {
Value::RootShapeIdentifier(v)
}
}
impl From<ShapeID> for Value {
fn from(v: ShapeID) -> Self {
Value::AbsoluteRootShapeIdentifier(v)
}
}
impl Value {
is_as! { text, Text, String }
is_as! { number, Number, Number }
is_as! { root_shape_id, RootShapeIdentifier, Identifier }
is_as! {
absolute_root_shape_id, AbsoluteRootShapeIdentifier, ShapeID
}
}
impl Display for KeyPathSegment {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
KeyPathSegment::Value(v) => v.to_string(),
KeyPathSegment::FunctionProperty(v) => format!("({})", v),
}
)
}
}
impl From<Value> for KeyPathSegment {
fn from(v: Value) -> Self {
Self::Value(v)
}
}
impl From<Identifier> for KeyPathSegment {
fn from(i: Identifier) -> Self {
Self::FunctionProperty(i)
}
}
impl KeyPathSegment {
is_as! { value, Value, Value }
is_as! { function_property, FunctionProperty, Identifier }
}
impl Display for Key {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}{}",
self.identifier,
if self.path.is_empty() {
String::new()
} else {
format!(
"|{}",
self.path()
.map(KeyPathSegment::to_string)
.collect::<Vec<String>>()
.join("|")
)
},
)
}
}
impl From<Identifier> for Key {
fn from(v: Identifier) -> Self {
Self {
identifier: v,
path: Default::default(),
}
}
}
impl Key {
pub fn new(identifier: Identifier) -> Self {
Self {
identifier,
path: Default::default(),
}
}
pub fn with_path(identifier: Identifier, path: &[KeyPathSegment]) -> Self {
Self {
identifier,
path: path.to_vec(),
}
}
required_member! { identifier, Identifier }
array_member! { path, path_segment, KeyPathSegment }
}
impl Display for Comparator {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Comparator::StringEqual => "=",
Comparator::StringNotEqual => "!=",
Comparator::StringStartsWith => "^=",
Comparator::StringEndsWith => "$=",
Comparator::StringContains => "*=",
Comparator::StringExists => "?=",
Comparator::NumberGreaterThan => ">",
Comparator::NumberGreaterOrEqual => ">=",
Comparator::NumberLessThan => "<",
Comparator::NumberLessOrEqual => "<=",
Comparator::ProjectionEqual => "{=}",
Comparator::ProjectionNotEqual => "{!=}",
Comparator::ProjectionSubset => "{<}",
Comparator::ProjectionProperSubset => "{<<}",
}
)
}
}
impl FromStr for Comparator {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"=" => Ok(Comparator::StringEqual),
"!=" => Ok(Comparator::StringNotEqual),
"^=" => Ok(Comparator::StringStartsWith),
"$=" => Ok(Comparator::StringEndsWith),
"*=" => Ok(Comparator::StringContains),
"?=" => Ok(Comparator::StringExists),
">" => Ok(Comparator::NumberGreaterThan),
">=" => Ok(Comparator::NumberGreaterOrEqual),
"<" => Ok(Comparator::NumberLessThan),
"<=" => Ok(Comparator::NumberLessOrEqual),
"{=}" => Ok(Comparator::ProjectionEqual),
"{!=}" => Ok(Comparator::ProjectionNotEqual),
"{<}" => Ok(Comparator::ProjectionSubset),
"{<<}" => Ok(Comparator::ProjectionProperSubset),
_ => Err(ErrorKind::InvalidSelectorExpression(s.to_string()).into()),
}
}
}
impl Display for AttributeComparison {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
" {} {}{}",
self.comparator,
self.rhs_values()
.map(Value::to_string)
.collect::<Vec<String>>()
.join(", "),
if self.case_insensitive {
" i".to_string()
} else {
String::new()
}
)
}
}
impl AttributeComparison {
pub fn new(comparator: Comparator, values: &[Value]) -> Self {
Self {
comparator,
rhs_values: values.to_vec(),
case_insensitive: false,
}
}
pub fn new_case_insensitive(comparator: Comparator, values: &[Value]) -> Self {
Self {
comparator,
rhs_values: values.to_vec(),
case_insensitive: true,
}
}
pub fn string_equal(rhs: Value) -> Self {
Self::new(Comparator::StringEqual, &[rhs])
}
pub fn string_not_equal(rhs: Value) -> Self {
Self::new(Comparator::StringNotEqual, &[rhs])
}
pub fn string_starts_with(rhs: Value) -> Self {
Self::new(
Comparator::StringStartsWith,
&[Value::Text(rhs.to_string())],
)
}
pub fn string_ends_with(rhs: Value) -> Self {
Self::new(Comparator::StringEndsWith, &[rhs])
}
pub fn string_contains(rhs: Value) -> Self {
Self::new(Comparator::StringContains, &[rhs])
}
pub fn string_exists(rhs: bool) -> Self {
Self::new(Comparator::StringExists, &[Value::Text(rhs.to_string())])
}
pub fn number_greater(rhs: Number) -> Self {
Self::new(Comparator::NumberGreaterThan, &[Value::Number(rhs)])
}
pub fn number_greater_or_equal(rhs: Number) -> Self {
Self::new(Comparator::NumberGreaterOrEqual, &[Value::Number(rhs)])
}
pub fn number_less(rhs: Number) -> Self {
Self::new(Comparator::NumberLessThan, &[Value::Number(rhs)])
}
pub fn number_less_or_equal(rhs: Number) -> Self {
Self::new(Comparator::NumberLessOrEqual, &[Value::Number(rhs)])
}
pub fn projection_equal(rhs: Value) -> Self {
Self::new(Comparator::ProjectionEqual, &[rhs])
}
pub fn projection_not_equal(rhs: Value) -> Self {
Self::new(Comparator::ProjectionNotEqual, &[rhs])
}
pub fn projection_subset(rhs: &[Value]) -> Self {
Self::new(Comparator::ProjectionSubset, rhs)
}
pub fn projection_proper_subset(rhs: &[Value]) -> Self {
Self::new(Comparator::ProjectionProperSubset, rhs)
}
required_member! { comparator, Comparator }
array_member! { rhs_values, value, Value }
boolean_member! { case_insensitive }
}
impl Display for AttributeSelector {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"[{}{}]",
self.key,
match &self.comparison {
None => String::new(),
Some(v) => v.to_string(),
}
)
}
}
impl From<Key> for AttributeSelector {
fn from(key: Key) -> Self {
Self {
key,
comparison: None,
}
}
}
impl From<AttributeSelector> for SelectorExpression {
fn from(v: AttributeSelector) -> Self {
SelectorExpression::AttributeSelector(v)
}
}
impl AttributeSelector {
pub fn new(key: Key) -> Self {
Self {
key,
comparison: None,
}
}
pub fn with_comparison(key: Key, comparison: AttributeComparison) -> Self {
Self {
key,
comparison: Some(comparison),
}
}
required_member! { key, Key }
optional_member! {
comparison, AttributeComparison
}
}
impl Display for SelectorExpression {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
SelectorExpression::ShapeType(v) => v.to_string(),
SelectorExpression::AttributeSelector(v) => v.to_string(),
SelectorExpression::ScopedAttributeSelector(v) => v.to_string(),
SelectorExpression::NeighborSelector(v) => v.to_string(),
SelectorExpression::Function(v) => v.to_string(),
SelectorExpression::VariableDefinition(v) => v.to_string(),
SelectorExpression::VariableReference(v) => v.to_string(),
}
)
}
}
impl SelectorExpression {
is_as! { shape_type, ShapeType, ShapeType }
is_as! { attribute_selector, AttributeSelector, AttributeSelector }
is_as! {
scoped_attribute_selector, ScopedAttributeSelector, ScopedAttributeSelector
}
is_as! { neighbor_selector, NeighborSelector, NeighborSelector }
is_as! { function, Function, Function }
is_as! {
variable_definition, VariableDefinition, VariableDefinition
}
is_as! { variable_reference, VariableReference, VariableReference }
}
impl Default for Selector {
fn default() -> Self {
Self {
expressions: Default::default(),
}
}
}
impl Display for Selector {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
self.expressions()
.map(SelectorExpression::to_string)
.collect::<Vec<String>>()
.join(" ")
)
}
}
impl From<SelectorExpression> for Selector {
fn from(v: SelectorExpression) -> Self {
Self {
expressions: vec![v],
}
}
}
impl From<Vec<SelectorExpression>> for Selector {
fn from(v: Vec<SelectorExpression>) -> Self {
Self { expressions: v }
}
}
impl Selector {
array_member! {
expressions, expression, SelectorExpression
}
}
impl Display for ScopedAttributeSelector {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"[@{}: {}]",
match &self.key {
None => String::new(),
Some(key) => key.to_string(),
},
self.assertions
.iter()
.map(ScopedAttributeAssertion::to_string)
.collect::<Vec<String>>()
.join(" && ")
)
}
}
impl From<ScopedAttributeSelector> for SelectorExpression {
fn from(v: ScopedAttributeSelector) -> Self {
SelectorExpression::ScopedAttributeSelector(v)
}
}
impl ScopedAttributeSelector {
pub fn new(assertions: &[ScopedAttributeAssertion]) -> Self {
assert!(!assertions.is_empty());
Self {
key: None,
assertions: assertions.to_vec(),
}
}
pub fn with_key(key: Key, assertions: &[ScopedAttributeAssertion]) -> Self {
assert!(!assertions.is_empty());
Self {
key: Some(key),
assertions: assertions.to_vec(),
}
}
optional_member! { key, Key }
array_member! {
assertions, assertion, ScopedAttributeAssertion
}
}
impl Display for ScopedValue {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
ScopedValue::Value(v) => v.to_string(),
ScopedValue::ContextValue(v) => format!(
"@{{{}}}",
v.iter()
.map(KeyPathSegment::to_string)
.collect::<Vec<String>>()
.join("|")
),
}
)
}
}
impl From<String> for ScopedValue {
fn from(v: String) -> Self {
Value::Text(v).into()
}
}
impl From<&str> for ScopedValue {
fn from(v: &str) -> Self {
Value::Text(v.to_string()).into()
}
}
impl From<Number> for ScopedValue {
fn from(v: Number) -> Self {
Value::Number(v).into()
}
}
impl From<i64> for ScopedValue {
fn from(v: i64) -> Self {
Value::Number(v.into()).into()
}
}
impl From<f64> for ScopedValue {
fn from(v: f64) -> Self {
Value::Number(v.into()).into()
}
}
impl From<Identifier> for ScopedValue {
fn from(v: Identifier) -> Self {
Value::RootShapeIdentifier(v).into()
}
}
impl From<ShapeID> for ScopedValue {
fn from(v: ShapeID) -> Self {
Value::AbsoluteRootShapeIdentifier(v).into()
}
}
impl From<Value> for ScopedValue {
fn from(v: Value) -> Self {
ScopedValue::Value(v)
}
}
impl From<Vec<KeyPathSegment>> for ScopedValue {
fn from(v: Vec<KeyPathSegment>) -> Self {
ScopedValue::ContextValue(v)
}
}
impl From<&[KeyPathSegment]> for ScopedValue {
fn from(v: &[KeyPathSegment]) -> Self {
ScopedValue::ContextValue(v.to_vec())
}
}
impl ScopedValue {
is_as! { value, Value, Value }
is_as_array! { context_value, ContextValue, KeyPathSegment }
}
impl Display for ScopedAttributeAssertion {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{} {} {}{}",
self.lhs_value,
self.comparator,
self.rhs_values()
.map(ScopedValue::to_string)
.collect::<Vec<String>>()
.join(", "),
if self.case_insensitive {
" i".to_string()
} else {
String::new()
}
)
}
}
impl ScopedAttributeAssertion {
pub fn new(lhs_value: ScopedValue, comparator: Comparator, rhs_values: &[ScopedValue]) -> Self {
Self {
lhs_value,
comparator,
rhs_values: rhs_values.to_vec(),
case_insensitive: false,
}
}
pub fn new_case_insensitive(
lhs_value: ScopedValue,
comparator: Comparator,
rhs_values: &[ScopedValue],
) -> Self {
Self {
lhs_value,
comparator,
rhs_values: rhs_values.to_vec(),
case_insensitive: true,
}
}
pub fn string_equal(lhs: ScopedValue, rhs: ScopedValue) -> Self {
Self::new(lhs, Comparator::StringEqual, &[rhs])
}
pub fn string_not_equal(lhs: ScopedValue, rhs: ScopedValue) -> Self {
Self::new(lhs, Comparator::StringNotEqual, &[rhs])
}
pub fn string_starts_with(lhs: ScopedValue, rhs: ScopedValue) -> Self {
Self::new(
lhs,
Comparator::StringStartsWith,
&[Value::Text(rhs.to_string()).into()],
)
}
pub fn string_ends_with(lhs: ScopedValue, rhs: ScopedValue) -> Self {
Self::new(lhs, Comparator::StringEndsWith, &[rhs])
}
pub fn string_contains(lhs: ScopedValue, rhs: ScopedValue) -> Self {
Self::new(lhs, Comparator::StringContains, &[rhs])
}
pub fn string_exists(lhs: ScopedValue, rhs: bool) -> Self {
Self::new(
lhs,
Comparator::StringExists,
&[Value::Text(rhs.to_string()).into()],
)
}
pub fn number_greater(lhs: ScopedValue, rhs: Number) -> Self {
Self::new(
lhs,
Comparator::NumberGreaterThan,
&[Value::Text(rhs.to_string()).into()],
)
}
pub fn number_greater_or_equal(lhs: ScopedValue, rhs: Number) -> Self {
Self::new(
lhs,
Comparator::NumberGreaterOrEqual,
&[Value::Text(rhs.to_string()).into()],
)
}
pub fn number_less(lhs: ScopedValue, rhs: Number) -> Self {
Self::new(
lhs,
Comparator::NumberLessThan,
&[Value::Text(rhs.to_string()).into()],
)
}
pub fn number_less_or_equal(lhs: ScopedValue, rhs: Number) -> Self {
Self::new(
lhs,
Comparator::NumberLessOrEqual,
&[Value::Text(rhs.to_string()).into()],
)
}
pub fn projection_equal(lhs: ScopedValue, rhs: ScopedValue) -> Self {
Self::new(lhs, Comparator::ProjectionEqual, &[rhs])
}
pub fn projection_not_equal(lhs: ScopedValue, rhs: ScopedValue) -> Self {
Self::new(lhs, Comparator::ProjectionNotEqual, &[rhs])
}
pub fn projection_subset(lhs: ScopedValue, rhs: &[ScopedValue]) -> Self {
Self::new(lhs, Comparator::ProjectionSubset, rhs)
}
pub fn projection_proper_subset(lhs: ScopedValue, rhs: &[ScopedValue]) -> Self {
Self::new(lhs, Comparator::ProjectionProperSubset, rhs)
}
required_member! { lhs_value, ScopedValue }
required_member! { comparator, Comparator }
array_member! { rhs_values, value, ScopedValue }
boolean_member! { case_insensitive }
}
impl Display for NeighborSelector {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
NeighborSelector::ForwardUndirected => ">".to_string(),
NeighborSelector::ReverseUndirected => "<".to_string(),
NeighborSelector::ForwardDirected(vs) => format!(
"-[{}]->",
vs.iter()
.map(Identifier::to_string)
.collect::<Vec<String>>()
.join(", ")
),
NeighborSelector::ReverseDirected(vs) => format!(
"<-[{}]-",
vs.iter()
.map(Identifier::to_string)
.collect::<Vec<String>>()
.join(", ")
),
NeighborSelector::ForwardRecursiveDirected => "~>".to_string(),
}
)
}
}
impl From<NeighborSelector> for SelectorExpression {
fn from(v: NeighborSelector) -> Self {
SelectorExpression::NeighborSelector(v)
}
}
impl NeighborSelector {
is_only! { forward_undirected, ForwardUndirected }
is_only! { reverse_undirected, ReverseUndirected }
is_only! { forward_recursive_directed, ForwardRecursiveDirected }
is_as_array! { forward_directed, ForwardDirected, Identifier }
is_as_array! { reverse_directed, ReverseDirected, Identifier }
}
impl Display for Function {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
":{}({})",
self.name,
self.arguments
.iter()
.map(Selector::to_string)
.collect::<Vec<String>>()
.join(", ")
)
}
}
impl From<Function> for SelectorExpression {
fn from(v: Function) -> Self {
SelectorExpression::Function(v)
}
}
impl Function {
pub fn new(name: Identifier, arguments: &[Selector]) -> Self {
assert!(!arguments.is_empty());
Self {
name,
arguments: arguments.to_vec(),
}
}
required_member! { name, Identifier }
array_member! {
arguments, argument, Selector
}
}
impl Display for VariableDefinition {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "${}({})", self.name, self.selector,)
}
}
impl From<VariableDefinition> for SelectorExpression {
fn from(v: VariableDefinition) -> Self {
SelectorExpression::VariableDefinition(v)
}
}
impl VariableDefinition {
pub fn new(name: Identifier, selector: Selector) -> Self {
Self { name, selector }
}
required_member! { name, Identifier }
required_member! { selector, Selector }
pub fn new_reference(&self) -> VariableReference {
VariableReference::new(self.name.clone())
}
}
impl Display for VariableReference {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "${{{}}}", self.name)
}
}
impl From<VariableReference> for SelectorExpression {
fn from(v: VariableReference) -> Self {
SelectorExpression::VariableReference(v)
}
}
impl From<Identifier> for VariableReference {
fn from(v: Identifier) -> Self {
VariableReference::new(v)
}
}
impl VariableReference {
pub fn new(name: Identifier) -> Self {
Self { name }
}
required_member! { name, Identifier }
}