formualizer_sheetport/
value.rs1use formualizer_common::LiteralValue;
2use std::collections::BTreeMap;
3
4#[derive(Debug, Clone, PartialEq)]
6pub enum PortValue {
7 Scalar(LiteralValue),
8 Record(BTreeMap<String, LiteralValue>),
9 Range(Vec<Vec<LiteralValue>>),
10 Table(TableValue),
11}
12
13impl PortValue {
14 pub fn as_scalar(&self) -> Option<&LiteralValue> {
15 match self {
16 PortValue::Scalar(value) => Some(value),
17 _ => None,
18 }
19 }
20
21 pub fn as_record(&self) -> Option<&BTreeMap<String, LiteralValue>> {
22 match self {
23 PortValue::Record(map) => Some(map),
24 _ => None,
25 }
26 }
27
28 pub fn as_range(&self) -> Option<&[Vec<LiteralValue>]> {
29 match self {
30 PortValue::Range(rows) => Some(rows),
31 _ => None,
32 }
33 }
34
35 pub fn as_table(&self) -> Option<&TableValue> {
36 match self {
37 PortValue::Table(table) => Some(table),
38 _ => None,
39 }
40 }
41
42 pub fn is_empty(&self) -> bool {
44 match self {
45 PortValue::Scalar(value) => matches!(value, LiteralValue::Empty),
46 PortValue::Record(fields) => fields
47 .values()
48 .all(|value| matches!(value, LiteralValue::Empty)),
49 PortValue::Range(rows) => {
50 if rows.is_empty() {
51 return true;
52 }
53 rows.iter()
54 .all(|row| row.iter().all(|cell| matches!(cell, LiteralValue::Empty)))
55 }
56 PortValue::Table(table) => table.is_empty(),
57 }
58 }
59}
60
61#[derive(Debug, Clone, PartialEq, Default)]
63pub struct TableValue {
64 pub rows: Vec<TableRow>,
65}
66
67impl TableValue {
68 pub fn new(rows: Vec<TableRow>) -> Self {
69 Self { rows }
70 }
71
72 pub fn is_empty(&self) -> bool {
73 self.rows.is_empty() || self.rows.iter().all(TableRow::is_empty)
74 }
75}
76
77#[derive(Debug, Clone, PartialEq, Default)]
79pub struct TableRow {
80 pub values: BTreeMap<String, LiteralValue>,
81}
82
83impl TableRow {
84 pub fn new(values: BTreeMap<String, LiteralValue>) -> Self {
85 Self { values }
86 }
87
88 pub fn get(&self, column: &str) -> Option<&LiteralValue> {
89 self.values.get(column)
90 }
91
92 pub fn is_empty(&self) -> bool {
93 self.values
94 .values()
95 .all(|value| matches!(value, LiteralValue::Empty))
96 }
97}
98
99#[derive(Debug, Clone, PartialEq, Default)]
101pub struct InputSnapshot(pub BTreeMap<String, PortValue>);
102
103impl InputSnapshot {
104 pub fn new(map: BTreeMap<String, PortValue>) -> Self {
105 Self(map)
106 }
107
108 pub fn inner(&self) -> &BTreeMap<String, PortValue> {
109 &self.0
110 }
111
112 pub fn into_inner(self) -> BTreeMap<String, PortValue> {
113 self.0
114 }
115
116 pub fn to_update(&self) -> InputUpdate {
117 InputUpdate(self.0.clone())
118 }
119
120 pub fn get(&self, id: &str) -> Option<&PortValue> {
121 self.0.get(id)
122 }
123}
124
125#[derive(Debug, Clone, PartialEq, Default)]
127pub struct OutputSnapshot(pub BTreeMap<String, PortValue>);
128
129impl OutputSnapshot {
130 pub fn new(map: BTreeMap<String, PortValue>) -> Self {
131 Self(map)
132 }
133
134 pub fn inner(&self) -> &BTreeMap<String, PortValue> {
135 &self.0
136 }
137
138 pub fn into_inner(self) -> BTreeMap<String, PortValue> {
139 self.0
140 }
141
142 pub fn get(&self, id: &str) -> Option<&PortValue> {
143 self.0.get(id)
144 }
145}
146
147#[derive(Debug, Clone, PartialEq, Default)]
149pub struct InputUpdate(pub BTreeMap<String, PortValue>);
150
151impl InputUpdate {
152 pub fn new() -> Self {
153 Self(BTreeMap::new())
154 }
155
156 pub fn insert(&mut self, id: impl Into<String>, value: PortValue) {
157 self.0.insert(id.into(), value);
158 }
159
160 pub fn into_inner(self) -> BTreeMap<String, PortValue> {
161 self.0
162 }
163
164 pub fn is_empty(&self) -> bool {
165 self.0.is_empty()
166 }
167}