1use crate::{
2 Cell, CellValue,
3 error::{CResult, Error},
4 parser::parse_cell_file,
5 query::{find_block, find_keyvalue, value_as_bool, value_as_f64, value_as_i32,
6 value_as_string, value_as_u32},
7};
8
9pub trait FromCellValue: Sized {
15 fn from_cell_value(value: &CellValue<'_>) -> CResult<Self>;
16}
17
18pub trait FromBlock: Sized {
24 const BLOCK_NAME: &'static str;
25
26 const BLOCK_ALIASES: &'static [&'static str] = &[];
30
31 fn from_block_rows(rows: &[CellValue<'_>]) -> CResult<Self>;
32
33 fn from_cells(tokens: &[Cell<'_>]) -> CResult<Self> {
35 match find_block(tokens, Self::BLOCK_NAME) {
36 Ok(rows) => Self::from_block_rows(rows),
37 Err(Error::KeyNotFound(_)) => {
38 for alias in Self::BLOCK_ALIASES {
39 if let Ok(rows) = find_block(tokens, alias) {
40 return Self::from_block_rows(rows);
41 }
42 }
43 Err(Error::KeyNotFound(Self::BLOCK_NAME.to_string()))
44 }
45 Err(e) => Err(e),
46 }
47 }
48}
49
50pub trait FromKeyValue: Sized {
55 const KEY_NAME: &'static str;
56
57 const KEY_ALIASES: &'static [&'static str] = &[];
60
61 fn from_cell_value_kv(value: &CellValue<'_>) -> CResult<Self>;
62
63 fn from_cells(tokens: &[Cell<'_>]) -> CResult<Option<Self>> {
65 match find_keyvalue(tokens, Self::KEY_NAME) {
66 Ok(v) => Self::from_cell_value_kv(v).map(Some),
67 Err(Error::KeyNotFound(_)) => {
68 for alias in Self::KEY_ALIASES {
69 if let Ok(v) = find_keyvalue(tokens, alias) {
70 return Self::from_cell_value_kv(v).map(Some);
71 }
72 }
73 Ok(None)
74 }
75 Err(e) => Err(e),
76 }
77 }
78}
79
80pub trait FromCellFile: Sized {
82 fn from_cell_file(tokens: &[Cell<'_>]) -> CResult<Self>;
83}
84
85pub fn parse<T: FromCellFile>(input: &str) -> CResult<T> {
89 let tokens =
90 parse_cell_file(input).map_err(|errors| Error::Message(format!("{errors:?}")))?;
91 T::from_cell_file(&tokens)
92}
93
94impl FromCellValue for f64 {
97 fn from_cell_value(value: &CellValue<'_>) -> CResult<Self> {
98 value_as_f64(value)
99 }
100}
101
102impl FromCellValue for u32 {
103 fn from_cell_value(value: &CellValue<'_>) -> CResult<Self> {
104 value_as_u32(value)
105 }
106}
107
108impl FromCellValue for i32 {
109 fn from_cell_value(value: &CellValue<'_>) -> CResult<Self> {
110 value_as_i32(value)
111 }
112}
113
114impl FromCellValue for bool {
115 fn from_cell_value(value: &CellValue<'_>) -> CResult<Self> {
116 value_as_bool(value)
117 }
118}
119
120impl FromCellValue for String {
121 fn from_cell_value(value: &CellValue<'_>) -> CResult<Self> {
122 value_as_string(value)
123 }
124}
125
126impl<T: FromCellValue, const N: usize> FromCellValue for [T; N] {
130 fn from_cell_value(value: &CellValue<'_>) -> CResult<Self> {
131 match value {
132 CellValue::Array(arr) => {
133 if arr.len() < N {
134 return Err(Error::Message(format!(
135 "expected array of length {N}, got {}",
136 arr.len()
137 )));
138 }
139 let items: Vec<T> = arr
141 .iter()
142 .take(N)
143 .map(T::from_cell_value)
144 .collect::<CResult<Vec<T>>>()?;
145 items.try_into().map_err(|_| {
146 Error::Message(format!("failed to convert Vec to [{N}] array"))
147 })
148 }
149 other => Err(Error::UnexpectedType(
150 format!("Array[{N}]"),
151 format!("{other:?}"),
152 )),
153 }
154 }
155}