1use http::uri::InvalidUri;
4use thiserror::Error;
5use tierkreis_core::{graph::GraphBuilderError, symbol::SymbolError};
6
7pub mod graph;
8pub mod messages;
9pub mod protos_gen;
10pub mod signature;
11mod worker;
12
13#[derive(Debug, Error)]
15pub enum ConvertError {
16 #[error("failed to parse protobuf")]
18 ProtoError,
19 #[error("malformed graph in protobuf: {0}")]
22 GraphError(GraphBuilderError),
23 #[error("invalid symbol in protobuf: {0}")]
25 SymbolError(SymbolError),
26 #[error("unexpected type errors")]
30 UnexpectedTypeErrors,
31 #[error("invalid uri: {0}")]
35 InvalidUri(#[from] InvalidUri),
36 #[error("nodeid invalid")]
39 InvalidNodeId,
40}
41
42impl From<GraphBuilderError> for ConvertError {
43 fn from(error: GraphBuilderError) -> Self {
44 ConvertError::GraphError(error)
45 }
46}
47
48impl From<SymbolError> for ConvertError {
49 fn from(error: SymbolError) -> Self {
50 ConvertError::SymbolError(error)
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use crate::protos_gen::v1alpha1::graph::*;
57 use rstest::{fixture, rstest};
58 use std::error::Error;
59 use tierkreis_core::graph::{self as core, GraphBuilder};
60 use tierkreis_core::prelude::{TryFrom, TryInto};
61 use tierkreis_core::symbol as cs;
62
63 #[fixture]
64 fn wee_graph() -> anyhow::Result<core::Graph> {
65 let mut builder = GraphBuilder::new();
68 let [input, output] = core::Graph::boundary();
69
70 builder.set_name("wee_graph".into());
71 builder.set_io_order([
72 vec![TryInto::try_into("value")?],
73 vec![TryInto::try_into("value")?],
74 ]);
75 let add = builder.add_node("add")?;
76 let one = builder.add_node(core::Value::Int(1))?;
77
78 builder.add_edge((input, "value"), (add, "a"), core::Type::Int)?;
79 builder.add_edge((one, "value"), (add, "b"), core::Type::Int)?;
80 builder.add_edge((add, "out"), (output, "value"), core::Type::Int)?;
81
82 Ok(builder.build()?)
83 }
84
85 #[rstest]
86 fn graph_roundtrip_to_file(
87 wee_graph: anyhow::Result<core::Graph>,
88 ) -> Result<(), Box<dyn Error>> {
89 extern crate prost;
90
91 use prost::Message;
92
93 use prost::bytes::BytesMut;
94 use std::fs::File;
95 use std::io::{Read, Write};
96
97 let core_graph = wee_graph?;
98
99 let g = Graph::from(core_graph.clone());
101
102 let capacity = g.encoded_len();
103 let mut buffer = Vec::with_capacity(capacity);
104 g.encode(&mut buffer)?;
105
106 let mut file = File::create("test0.tk")?;
107 file.write_all(&buffer)?;
108 file.flush()?;
109 let mut file2 = File::open("test0.tk")?;
110 let mut new_buff = Vec::new();
112 file2.read_to_end(&mut new_buff)?;
113 let mut new_buff = BytesMut::from(&new_buff[..]);
115 let g_new = Graph::decode(&mut new_buff)?;
116
117 let new_core_g: core::Graph = TryInto::try_into(g_new).unwrap();
118
119 assert_eq!(new_core_g, core_graph);
120
121 std::fs::remove_file("test0.tk")?;
122 Ok(())
123 }
124
125 #[rstest]
126 #[case(core::Value::Int(1))]
127 #[case(core::Value::Bool(false))]
128 #[case(core::Value::Str("test123".to_string()))]
129 #[case(core::Value::Pair(Box::new((core::Value::Bool(true), core::Value::Int(3)))))]
130 #[case(core::Value::Map(
131 [
132 (core::Value::Int(1), core::Value::Bool(true)),
133 (core::Value::Int(2), core::Value::Bool(false)),
134 ]
135 .iter()
136 .cloned()
137 .collect(),
138 ))]
139 #[case(core::Value::Vec(vec![core::Value::Int(1), core::Value::Int(2), core::Value::Int(3)]))]
140 #[case(core::Value::Variant(TryInto::try_into("mytag").unwrap(), Box::new(core::Value::Int(2))))]
141 fn value_roundtrip(#[case] start: core::Value) {
142 let start_converted: Value = start.clone().into();
143 let reverse_converted =
144 <core::Value as TryFrom<_>>::try_from(start_converted).expect("Conversion Failed");
145 assert_eq!(start, reverse_converted);
146 }
147
148 #[rstest]
149 #[case(core::Node::Box(cs::Location::local(), wee_graph()?))]
150 #[case(cs::FunctionName::builtin(TryInto::try_into("foo")?).into())]
151 #[case((cs::FunctionName { prefixes: vec![TryInto::try_into("remote")?], name: TryInto::try_into("foo")? }, 3).into())]
152 fn node_roundtrip(#[case] start: core::Node) -> Result<(), Box<dyn Error>> {
153 let pb_node: Node = start.clone().into();
154 let roundtripped: core::Node = TryInto::try_into(pb_node).expect("Deserialization failed");
155 assert_eq!(start, roundtripped);
156 Ok(())
157 }
158}