summaryrefslogtreecommitdiff
path: root/src/sheet/cell.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/sheet/cell.rs')
-rw-r--r--src/sheet/cell.rs198
1 files changed, 198 insertions, 0 deletions
diff --git a/src/sheet/cell.rs b/src/sheet/cell.rs
new file mode 100644
index 0000000..413e299
--- /dev/null
+++ b/src/sheet/cell.rs
@@ -0,0 +1,198 @@
+use std::fmt::Display;
+
+use mlua::{FromLua, IntoLua, UserData, Value};
+
+use super::register::{Register, SheetId};
+
+#[derive(Debug, Clone)]
+pub enum Cell {
+ String(String),
+ Number(f64),
+}
+
+impl Cell {
+ pub fn new_empty() -> Self {
+ Cell::String("".to_string())
+ }
+}
+
+impl<'lua> IntoLua<'lua> for Cell {
+ fn into_lua(self, lua: &'lua mlua::Lua) -> mlua::Result<mlua::Value<'lua>> {
+ match self {
+ Cell::String(s) => s.into_lua(lua),
+ Cell::Number(n) => n.into_lua(lua),
+ }
+ }
+}
+
+impl<'lua> FromLua<'lua> for Cell {
+ fn from_lua(value: mlua::Value<'lua>, _: &'lua mlua::Lua) -> mlua::Result<Self> {
+ match value {
+ Value::Nil => Ok(Cell::new_empty()),
+ Value::Boolean(b) => Ok(Cell::String(b.to_string())),
+ Value::Integer(n) => Ok(Cell::String(n.to_string())),
+ Value::Number(n) => Ok(Cell::String(n.to_string())),
+ Value::String(s) => Ok(Cell::String(s.to_str()?.to_string())),
+ _ => Err(mlua::Error::runtime(
+ "cell content must be number or string",
+ )),
+ }
+ }
+}
+
+impl Display for Cell {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Cell::String(s) => s.fmt(f),
+ Cell::Number(n) => n.fmt(f),
+ }
+ }
+}
+
+impl From<String> for Cell {
+ fn from(value: String) -> Self {
+ Cell::String(value.clone())
+ }
+}
+
+impl From<&str> for Cell {
+ fn from(value: &str) -> Self {
+ Cell::String(value.to_string())
+ }
+}
+
+macro_rules! cell_from_integer {
+ ($($number:ty),+ $(,)?) => {
+ $(
+ impl From<$number> for Cell {
+ fn from(value: $number) -> Self {
+ Cell::Number(value as f64)
+ }
+ }
+ )*
+ };
+}
+
+#[rustfmt::skip]
+cell_from_integer!(
+ i8, i16, i32, i64, i128, isize,
+ u8, u16, u32, u64, u128, usize,
+ f32, f64
+);
+
+#[derive(Debug, Clone, Copy)]
+pub struct CellRef {
+ row: usize,
+ column: usize,
+ sheet_id: SheetId,
+}
+
+impl CellRef {
+ pub fn new(sheet_id: SheetId, row: usize, column: usize) -> Option<Self> {
+ Register::get(sheet_id)
+ .map(|sheet| {
+ sheet.read().unwrap().get_cell(row, column).map(|_| Self {
+ sheet_id,
+ row,
+ column,
+ })
+ })
+ .unwrap_or(None)
+ }
+
+ pub fn value(&self) -> Cell {
+ return Register::get(self.sheet_id)
+ .unwrap()
+ .read()
+ .unwrap()
+ .get_cell(self.row, self.column)
+ .unwrap()
+ .clone();
+ }
+
+ pub fn set_value(&mut self, value: Cell) {
+ Register::get(self.sheet_id)
+ .unwrap()
+ .write()
+ .unwrap()
+ .set_cell(self.row, self.column, value);
+ }
+
+ pub fn left(&self) -> Option<Self> {
+ if self.column > 0 {
+ Self::new(self.sheet_id, self.row, self.column - 1)
+ } else {
+ None
+ }
+ }
+
+ pub fn right(&self) -> Option<Self> {
+ Self::new(self.sheet_id, self.row, self.column + 1)
+ }
+
+ pub fn up(&self) -> Option<Self> {
+ if self.row > 0 {
+ Self::new(self.sheet_id, self.row - 1, self.column)
+ } else {
+ None
+ }
+ }
+
+ pub fn down(&self) -> Option<Self> {
+ Self::new(self.sheet_id, self.row + 1, self.column)
+ }
+
+ pub fn begin(&self) -> Option<Self> {
+ Self::new(self.sheet_id, self.row, 0)
+ }
+
+ pub fn end(&self) -> Option<Self> {
+ Self::new(
+ self.sheet_id,
+ self.row,
+ Register::get(self.sheet_id)
+ .unwrap()
+ .read()
+ .unwrap()
+ .width()
+ - 1,
+ )
+ }
+
+ pub fn top(&self) -> Option<Self> {
+ Self::new(self.sheet_id, 0, self.column)
+ }
+
+ pub fn bottom(&self) -> Option<Self> {
+ Self::new(
+ self.sheet_id,
+ Register::get(self.sheet_id)
+ .unwrap()
+ .read()
+ .unwrap()
+ .height()
+ - 1,
+ self.column,
+ )
+ }
+}
+
+impl UserData for CellRef
+where
+ Self: Sized,
+{
+ fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) {
+ fields.add_field_method_get("row", |_, this| Ok(this.row));
+ fields.add_field_method_get("column", |_, this| Ok(this.column));
+ fields.add_field_method_get("value", |_, this| Ok(this.value()));
+ fields.add_field_method_set("value", |_, this, value| Ok(this.set_value(value)));
+ fields.add_field_method_get("left", |lua, this| this.left().into_lua(lua));
+ fields.add_field_method_get("right", |lua, this| this.right().into_lua(lua));
+ fields.add_field_method_get("up", |lua, this| this.up().into_lua(lua));
+ fields.add_field_method_get("down", |lua, this| this.down().into_lua(lua));
+ fields.add_field_method_get("begin", |lua, this| this.begin().into_lua(lua));
+ fields.add_field_method_get("end", |lua, this| this.end().into_lua(lua));
+ fields.add_field_method_get("top", |lua, this| this.top().into_lua(lua));
+ fields.add_field_method_get("bottom", |lua, this| this.bottom().into_lua(lua));
+ }
+}