use serde::{Deserialize, Serialize};
use crate::ast::{ReflectedValue, Value};
use crate::iteration::comprehension::ast::Comprehension;
use crate::iteration::comprehension::cardinality::CardinalityClass;
use crate::iteration::comprehension::metadata::Metadata;
use crate::iteration::comprehension::surfaces::{CompiledComprehension, CoordinateStream};
use crate::iteration::comprehension::validate::{Mode, ValidationError};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StreamerValue {
pub text: String,
pub ast: Comprehension,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub outer: Vec<String>,
}
impl StreamerValue {
pub fn new(text: impl Into<String>, ast: Comprehension) -> Self {
Self {
text: text.into(),
ast,
outer: Vec::new(),
}
}
pub fn in_scope(
text: impl Into<String>,
ast: Comprehension,
has: &dyn Fn(&str) -> bool,
) -> Self {
let mut outer: Vec<String> = crate::iteration::comprehension::validate::outer_reads(&ast)
.into_iter()
.filter(|r| !r.bare && has(&r.name))
.map(|r| r.name)
.collect();
outer.sort();
outer.dedup();
Self {
text: text.into(),
ast,
outer,
}
}
pub fn element_names(&self) -> Vec<String> {
self.ast.coordinate_names()
}
pub fn metadata(&self) -> Metadata {
self.ast.metadata()
}
pub fn cardinality(&self) -> CardinalityClass {
self.metadata().cardinality
}
pub fn compiled(&self) -> Result<CompiledComprehension, ValidationError> {
CompiledComprehension::from_ast_in(&self.ast, Mode::Permissive, &|name| {
self.outer.iter().any(|n| n == name)
})
.map(|(compiled, _)| compiled)
}
pub fn coordinate_stream(&self) -> Result<CoordinateStream, ValidationError> {
Ok(self.compiled()?.coordinate_stream())
}
pub fn to_json(&self) -> String {
serde_json::to_string(self).expect("StreamerValue serializes")
}
pub fn from_json(payload: &str) -> Self {
let trimmed = payload.trim();
if trimmed.starts_with('{') {
match serde_json::from_str::<Self>(trimmed) {
Ok(v) => return v,
Err(e) => panic!("streamer: malformed comprehension payload: {e}"),
}
}
match Self::parse_text(trimmed) {
Ok(v) => v,
Err(e) => panic!("streamer: `{trimmed}` is not a comprehension: {e}"),
}
}
pub fn parse_text(text: &str) -> Result<Self, String> {
let ast = crate::iteration::comprehension::spec::parse_comprehension_algebra(text)?;
Ok(Self::new(text, ast))
}
}
impl ReflectedValue for StreamerValue {
fn type_name(&self) -> &str {
"Streamer"
}
fn display(&self) -> String {
format!("for {}", self.text)
}
fn to_json_value(&self) -> serde_json::Value {
serde_json::json!({
"for": self.text,
"elements": self.element_names(),
"cardinality": format!("{:?}", self.cardinality()),
})
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn clone_reflected(&self) -> Box<dyn ReflectedValue> {
Box::new(self.clone())
}
}
impl Value {
pub fn from_streamer(s: StreamerValue) -> Self {
Value::Ext(Box::new(s))
}
pub fn as_streamer(&self) -> Option<&StreamerValue> {
match self {
Value::Ext(b) => b.as_any().downcast_ref::<StreamerValue>(),
_ => None,
}
}
}