use std::borrow::Cow;
use crate::graph::GraphStorage;
use crate::traversal::step::map_steps::temporal::{describe, held_value, replaced};
use crate::value::vector::vector_error;
use crate::value::{Vector, VectorElement, VectorError};
use crate::*;
fn incoming<'a, S: GraphStorage>(
context: &'a TraverserContext<'_, S>,
value: &'a TraverserValue<S>,
) -> TraverserResult<Result<Cow<'a, ElementProperty>, &'static str>> {
match value {
TraverserValue::Array(_) => Ok(Ok(Cow::Owned(value.into_node_property(context.storage)?))),
_ => held_value(context, value),
}
}
fn not_a_vector(step: &'static str, found: String) -> Box<TraverserError> {
vector_error(step, VectorError::NotAVector { found })
}
#[derive(Clone, Default)]
struct StepAsVector;
impl fmt::Display for StepAsVector {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("as_vector()")
}
}
fn as_vector_step<'g, S: GraphStorage + 'g>() -> GraphStep<'g, S> {
GraphStep::Map("as_vector", Box::new(StepAsVector))
}
impl<'g, S: GraphStorage + 'g> GraphStepMap<'g, S> for StepAsVector {
fn process(
&self,
context: &mut TraverserContext<'_, S>,
source: Traverser<S>,
) -> TraverserResult<Traverser<S>> {
let converted = match incoming(context, &source.value)? {
Ok(held) => match held.as_ref() {
ElementProperty::Null => ElementProperty::Null,
ElementProperty::Vector(vector) => ElementProperty::Vector(vector.clone()),
ElementProperty::Array(items) => ElementProperty::Vector(
Vector::from_values(items).map_err(|error| vector_error("as_vector", error))?,
),
other => return Err(not_a_vector("as_vector", describe(other))),
},
Err(kind) => return Err(not_a_vector("as_vector", format!("a {kind}"))),
};
Ok(replaced(source, TraverserValue::Computed(converted, None)))
}
fn may_filter(&self) -> bool {
true
}
fn clone_box(&self) -> Box<dyn GraphStepMap<'g, S> + 'g> {
Box::new(self.clone())
}
}
#[derive(Clone)]
struct StepQuantize {
element: VectorElement,
}
impl fmt::Display for StepQuantize {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"quantize({})",
crate::value::literal::rhai_string(self.element.name())
)
}
}
fn quantize_step<'g, S: GraphStorage + 'g>(element: VectorElement) -> GraphStep<'g, S> {
GraphStep::Map("quantize", Box::new(StepQuantize { element }))
}
impl<'g, S: GraphStorage + 'g> GraphStepMap<'g, S> for StepQuantize {
fn process(
&self,
context: &mut TraverserContext<'_, S>,
source: Traverser<S>,
) -> TraverserResult<Traverser<S>> {
let converted = match incoming(context, &source.value)? {
Ok(held) => match held.as_ref() {
ElementProperty::Null => ElementProperty::Null,
ElementProperty::Vector(vector) => ElementProperty::Vector(
vector
.quantize(self.element)
.map_err(|error| vector_error("quantize", error))?,
),
other => return Err(not_a_vector("quantize", describe(other))),
},
Err(kind) => return Err(not_a_vector("quantize", format!("a {kind}"))),
};
Ok(replaced(source, TraverserValue::Computed(converted, None)))
}
fn may_filter(&self) -> bool {
true
}
fn clone_box(&self) -> Box<dyn GraphStepMap<'g, S> + 'g> {
Box::new(self.clone())
}
}
impl<'g, S: GraphStorage + 'g> GraphTraversalSource<'g, S> {
pub fn as_vector(self) -> Self {
self.push_step(as_vector_step())
}
pub fn quantize(self, element: VectorElement) -> Self {
self.push_step(quantize_step(element))
}
}
impl __ {
pub fn as_vector<'g, S: GraphStorage + 'g>() -> AnonymousTraversal<'g, S> {
AnonymousTraversal::new().as_vector()
}
pub fn quantize<'g, S: GraphStorage + 'g>(element: VectorElement) -> AnonymousTraversal<'g, S> {
AnonymousTraversal::new().quantize(element)
}
}
impl<'g, S: GraphStorage + 'g> AnonymousTraversal<'g, S> {
pub fn as_vector(self) -> Self {
self.push_step(as_vector_step())
}
pub fn quantize(self, element: VectorElement) -> Self {
self.push_step(quantize_step(element))
}
}