serializer.rs
3.2 kB · rust · 94 lines
1use super::models::Cell2d;2use crate::dim::serializer::{byte_grid, color_grid, count_grid, parse, tag_layer, types_field};3use mrlycore::errors::{value_error, MrlyError, Result};4use mrlycore::json;5use mrlycore::tensor::Tensor;67/// Returns the cell's types as rows of bytes.8pub fn to_lists(cell: &Cell2d) -> Vec<Vec<u8>> {9 let (h, w) = (cell.height(), cell.width());10 (0..h)11 .map(|y| (0..w).map(|x| cell.types().get(&[y, x])).collect())12 .collect()13}1415/// Builds a cell from rows of bytes, or an error when the rows are empty or ragged.16pub fn from_lists(lists: &[Vec<u8>]) -> Result<Cell2d> {17 if lists.is_empty() {18 return value_error("cannot build a cell from an empty list.");19 }20 let (h, w) = (lists.len(), lists[0].len());21 if lists.iter().any(|row| row.len() != w) {22 return value_error("all rows must have the same length.");23 }24 let data: Vec<u8> = lists.iter().flatten().copied().collect();25 Ok(Cell2d::new(Tensor::of(data, vec![h, w])))26}2728/// Returns the cell's types as rows of digit strings.29pub fn to_strings(cell: &Cell2d) -> Vec<String> {30 to_lists(cell)31 .iter()32 .map(|row| row.iter().map(|v| v.to_string()).collect())33 .collect()34}3536/// Builds a cell from rows of digit strings, or an error at any non-digit.37///38/// ```39/// let rows = vec!["111".to_string(), "101".to_string(), "111".to_string()];40/// let cell = mrlymath::two::from_strings(&rows).unwrap();41/// assert_eq!(mrlymath::two::to_lists(&cell)[1], vec![1, 0, 1]);42/// ```43pub fn from_strings(rows: &[String]) -> Result<Cell2d> {44 let lists: Result<Vec<Vec<u8>>> = rows45 .iter()46 .map(|row| {47 row.chars()48 .map(|ch| {49 ch.to_digit(10)50 .map(|d| d as u8)51 .ok_or_else(|| MrlyError::Value(format!("invalid digit {ch:?}.")))52 })53 .collect()54 })55 .collect();56 from_lists(&lists?)57}5859/// Serializes the cell to a JSON string of its types, with colors and tags when present.60pub fn to_json(cell: &Cell2d) -> String {61 let mut data = json!({62 "v": 1,63 "width": cell.width(),64 "height": cell.height(),65 "types": to_lists(cell),66 });67 if let Some(colors) = &cell.cell.colors {68 data["colors"] = json!(colors.chunks(cell.width()).collect::<Vec<_>>());69 }70 if let Some(tags) = &cell.cell.tags {71 let (h, w) = (cell.height(), cell.width());72 let nested: Vec<Vec<i64>> = (0..h)73 .map(|r| (0..w).map(|c| tags.at(r * w + c)).collect())74 .collect();75 data["tags"] = json!(nested);76 }77 data.to_string()78}7980/// Restores a cell from its JSON string, colors and tags included, or a parse error.81pub fn from_json(text: &str) -> Result<Cell2d> {82 let data = parse(text)?;83 let lists = byte_grid(types_field(&data)?)?;84 let mut cell = from_lists(&lists)?;85 if let Some(colors) = data.get("colors") {86 let nested = color_grid(colors)?;87 cell.cell.colors = Some(nested.into_iter().flatten().collect());88 }89 if let Some(tags) = data.get("tags") {90 let shape = vec![cell.height(), cell.width()];91 cell.cell.tags = Some(tag_layer(&count_grid(tags)?, shape)?);92 }93 Ok(cell)94}