use std::borrow::Cow;
use std::fmt;
use crate::extensions::simple::{ExtensionFunction, SimpleExtensions};
#[derive(Debug, Clone)]
pub enum StructuralValue<'a> {
String(Cow<'a, str>),
Integer(i64),
Float(f64),
Boolean(bool),
Reference(i32),
Function(FunctionRef<'a>),
TableName(Vec<Cow<'a, str>>),
Tuple(Vec<StructuralValue<'a>>),
List(Vec<StructuralValue<'a>>),
Missing(Cow<'a, str>),
Enum(Cow<'a, str>),
}
#[derive(Debug, Clone)]
pub enum FunctionRef<'a> {
Unresolved(Cow<'a, str>),
UnresolvedWithAnchor { name: Cow<'a, str>, anchor: u32 },
UnresolvedWithUri { name: Cow<'a, str>, uri_anchor: u32 },
UnresolvedWithBoth {
name: Cow<'a, str>,
anchor: u32,
uri_anchor: u32,
},
Resolved {
name: Cow<'a, str>,
extension: &'a ExtensionFunction,
},
}
#[derive(Debug, Clone)]
pub struct NamedArg<'a> {
pub name: Cow<'a, str>,
pub value: StructuralValue<'a>,
}
#[derive(Debug, Clone)]
pub struct Arguments<'a> {
pub positional: Vec<StructuralValue<'a>>,
pub named: Vec<NamedArg<'a>>,
}
#[derive(Debug, Clone)]
pub enum ColumnSpec<'a> {
Named {
name: Cow<'a, str>,
type_spec: Option<Cow<'a, str>>,
},
Reference(i32),
Expression(StructuralValue<'a>),
}
impl<'a> StructuralValue<'a> {
pub fn string(s: impl Into<Cow<'a, str>>) -> Self {
Self::String(s.into())
}
pub fn owned_string(s: String) -> Self {
Self::String(Cow::Owned(s))
}
pub fn borrowed_string(s: &'a str) -> Self {
Self::String(Cow::Borrowed(s))
}
pub fn function(name: impl Into<Cow<'a, str>>) -> Self {
Self::Function(FunctionRef::Unresolved(name.into()))
}
pub fn function_with_anchor(name: impl Into<Cow<'a, str>>, anchor: u32) -> Self {
Self::Function(FunctionRef::UnresolvedWithAnchor {
name: name.into(),
anchor,
})
}
pub fn function_with_uri(name: impl Into<Cow<'a, str>>, uri_anchor: u32) -> Self {
Self::Function(FunctionRef::UnresolvedWithUri {
name: name.into(),
uri_anchor,
})
}
pub fn function_with_both(name: impl Into<Cow<'a, str>>, anchor: u32, uri_anchor: u32) -> Self {
Self::Function(FunctionRef::UnresolvedWithBoth {
name: name.into(),
anchor,
uri_anchor,
})
}
pub fn resolve_functions(&mut self, extensions: &'a SimpleExtensions) -> Result<(), String> {
match self {
StructuralValue::Function(func_ref) => {
*func_ref = func_ref.try_resolve(extensions)?;
}
StructuralValue::Tuple(values) | StructuralValue::List(values) => {
for value in values {
value.resolve_functions(extensions)?;
}
}
_ => {} }
Ok(())
}
pub fn into_owned(self) -> StructuralValue<'static> {
match self {
StructuralValue::String(s) => StructuralValue::String(Cow::Owned(s.into_owned())),
StructuralValue::Integer(i) => StructuralValue::Integer(i),
StructuralValue::Float(f) => StructuralValue::Float(f),
StructuralValue::Boolean(b) => StructuralValue::Boolean(b),
StructuralValue::Reference(r) => StructuralValue::Reference(r),
StructuralValue::Function(f) => StructuralValue::Function(f.into_owned()),
StructuralValue::TableName(names) => StructuralValue::TableName(
names
.into_iter()
.map(|n| Cow::Owned(n.into_owned()))
.collect(),
),
StructuralValue::Tuple(values) => {
StructuralValue::Tuple(values.into_iter().map(|v| v.into_owned()).collect())
}
StructuralValue::List(values) => {
StructuralValue::List(values.into_iter().map(|v| v.into_owned()).collect())
}
StructuralValue::Missing(msg) => StructuralValue::Missing(Cow::Owned(msg.into_owned())),
StructuralValue::Enum(e) => StructuralValue::Enum(Cow::Owned(e.into_owned())),
}
}
}
impl<'a> FunctionRef<'a> {
pub fn try_resolve(self, extensions: &'a SimpleExtensions) -> Result<Self, String> {
match self {
FunctionRef::Unresolved(name) => {
if let Some(ext_fn) = extensions.functions().find_by_name(&name) {
Ok(FunctionRef::Resolved {
name,
extension: ext_fn,
})
} else {
Ok(FunctionRef::Unresolved(name))
}
}
FunctionRef::UnresolvedWithAnchor { name, anchor } => {
if let Some(ext_fn) = extensions.functions().get(anchor) {
Ok(FunctionRef::Resolved {
name,
extension: ext_fn,
})
} else {
Ok(FunctionRef::UnresolvedWithAnchor { name, anchor })
}
}
other => Ok(other),
}
}
pub fn into_owned(self) -> FunctionRef<'static> {
match self {
FunctionRef::Unresolved(name) => FunctionRef::Unresolved(Cow::Owned(name.into_owned())),
FunctionRef::UnresolvedWithAnchor { name, anchor } => {
FunctionRef::UnresolvedWithAnchor {
name: Cow::Owned(name.into_owned()),
anchor,
}
}
FunctionRef::UnresolvedWithUri { name, uri_anchor } => FunctionRef::UnresolvedWithUri {
name: Cow::Owned(name.into_owned()),
uri_anchor,
},
FunctionRef::UnresolvedWithBoth {
name,
anchor,
uri_anchor,
} => FunctionRef::UnresolvedWithBoth {
name: Cow::Owned(name.into_owned()),
anchor,
uri_anchor,
},
FunctionRef::Resolved { name, extension: _ } => {
FunctionRef::Unresolved(Cow::Owned(name.into_owned()))
}
}
}
pub fn name(&self) -> &str {
match self {
FunctionRef::Unresolved(name) => name,
FunctionRef::UnresolvedWithAnchor { name, .. } => name,
FunctionRef::UnresolvedWithUri { name, .. } => name,
FunctionRef::UnresolvedWithBoth { name, .. } => name,
FunctionRef::Resolved { name, .. } => name,
}
}
}
impl<'a> Arguments<'a> {
pub fn new() -> Self {
Self {
positional: Vec::new(),
named: Vec::new(),
}
}
pub fn add_positional(&mut self, value: StructuralValue<'a>) {
self.positional.push(value);
}
pub fn add_named(&mut self, name: impl Into<Cow<'a, str>>, value: StructuralValue<'a>) {
self.named.push(NamedArg {
name: name.into(),
value,
});
}
pub fn is_empty(&self) -> bool {
self.positional.is_empty() && self.named.is_empty()
}
pub fn resolve_functions(&mut self, extensions: &'a SimpleExtensions) -> Result<(), String> {
for value in &mut self.positional {
value.resolve_functions(extensions)?;
}
for arg in &mut self.named {
arg.value.resolve_functions(extensions)?;
}
Ok(())
}
}
impl<'a> Default for Arguments<'a> {
fn default() -> Self {
Self::new()
}
}
impl<'a> ColumnSpec<'a> {
pub fn named(name: impl Into<Cow<'a, str>>) -> Self {
Self::Named {
name: name.into(),
type_spec: None,
}
}
pub fn named_with_type(
name: impl Into<Cow<'a, str>>,
type_spec: impl Into<Cow<'a, str>>,
) -> Self {
Self::Named {
name: name.into(),
type_spec: Some(type_spec.into()),
}
}
pub fn reference(index: i32) -> Self {
Self::Reference(index)
}
pub fn expression(expr: StructuralValue<'a>) -> Self {
Self::Expression(expr)
}
}
impl<'a> fmt::Display for StructuralValue<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
StructuralValue::String(s) => write!(f, "'{}'", s),
StructuralValue::Integer(i) => write!(f, "{}", i),
StructuralValue::Float(fl) => write!(f, "{}", fl),
StructuralValue::Boolean(b) => write!(f, "{}", b),
StructuralValue::Reference(r) => write!(f, "${}", r),
StructuralValue::Function(func) => write!(f, "{}", func),
StructuralValue::TableName(names) => {
write!(
f,
"{}",
names
.iter()
.map(|n| n.as_ref())
.collect::<Vec<_>>()
.join(".")
)
}
StructuralValue::Tuple(values) => {
write!(
f,
"({})",
values
.iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join(", ")
)
}
StructuralValue::List(values) => {
write!(
f,
"[{}]",
values
.iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join(", ")
)
}
StructuralValue::Missing(msg) => write!(f, "!{{{}}}", msg),
StructuralValue::Enum(e) => write!(f, "&{}", e),
}
}
}
impl<'a> fmt::Display for FunctionRef<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FunctionRef::Unresolved(name) => write!(f, "{}", name),
FunctionRef::UnresolvedWithAnchor { name, anchor } => write!(f, "{}#{}", name, anchor),
FunctionRef::UnresolvedWithUri { name, uri_anchor } => {
write!(f, "{}@{}", name, uri_anchor)
}
FunctionRef::UnresolvedWithBoth {
name,
anchor,
uri_anchor,
} => {
write!(f, "{}#{}@{}", name, anchor, uri_anchor)
}
FunctionRef::Resolved { name, .. } => write!(f, "{}", name),
}
}
}
impl<'a> fmt::Display for NamedArg<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}={}", self.name, self.value)
}
}
impl<'a> fmt::Display for Arguments<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut parts = Vec::new();
for value in &self.positional {
parts.push(value.to_string());
}
for arg in &self.named {
parts.push(arg.to_string());
}
write!(f, "{}", parts.join(", "))
}
}
impl<'a> fmt::Display for ColumnSpec<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ColumnSpec::Named { name, type_spec } => {
if let Some(type_spec) = type_spec {
write!(f, "{}:{}", name, type_spec)
} else {
write!(f, "{}", name)
}
}
ColumnSpec::Reference(r) => write!(f, "${}", r),
ColumnSpec::Expression(expr) => write!(f, "{}", expr),
}
}
}