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, compile};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StreamerValue {
pub text: String,
pub ast: Comprehension,
}
impl StreamerValue {
pub fn new(text: impl Into<String>, ast: Comprehension) -> Self {
Self {
text: text.into(),
ast,
}
}
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) -> CompiledComprehension {
compile(&self.ast)
}
pub fn coordinate_stream(&self) -> CoordinateStream {
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 legacy = crate::iteration::comprehension::parse::parse_comprehension_text(text)?;
let ast = crate::iteration::comprehension::spec::legacy_to_algebra(&legacy)
.map_err(|e| e.to_string())?;
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,
}
}
}