Compare commits
1 Commits
experiment
...
feature/ni
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d189905ba |
27
Cargo.lock
generated
27
Cargo.lock
generated
@@ -38,25 +38,6 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bincode"
|
|
||||||
version = "2.0.0-rc.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95"
|
|
||||||
dependencies = [
|
|
||||||
"bincode_derive",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bincode_derive"
|
|
||||||
version = "2.0.0-rc.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7e30759b3b99a1b802a7a3aa21c85c3ded5c28e1c83170d82d70f08bbf7f3e4c"
|
|
||||||
dependencies = [
|
|
||||||
"virtue",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.14.0"
|
version = "3.14.0"
|
||||||
@@ -210,7 +191,6 @@ dependencies = [
|
|||||||
name = "ironcalc"
|
name = "ironcalc"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
|
||||||
"chrono",
|
"chrono",
|
||||||
"ironcalc_base",
|
"ironcalc_base",
|
||||||
"itertools",
|
"itertools",
|
||||||
@@ -226,7 +206,6 @@ dependencies = [
|
|||||||
name = "ironcalc_base"
|
name = "ironcalc_base"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
|
||||||
"chrono",
|
"chrono",
|
||||||
"chrono-tz",
|
"chrono-tz",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
@@ -562,12 +541,6 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "virtue"
|
|
||||||
version = "0.0.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9dcc60c0624df774c82a0ef104151231d37da4962957d691c011c852b2473314"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.10.0+wasi-snapshot-preview1"
|
version = "0.10.0+wasi-snapshot-preview1"
|
||||||
|
|||||||
50
README.md
50
README.md
@@ -117,7 +117,55 @@ See more examples in the `examples` folder of the xlsx crate.
|
|||||||
|
|
||||||
# ROADMAP
|
# ROADMAP
|
||||||
|
|
||||||
See https://github.com/ironcalc
|
> [!WARNING]
|
||||||
|
> This is work-in-progress. IronCalc in developed in the open. Expect things to be broken and change quickly until version 0.5
|
||||||
|
|
||||||
|
Major milestones:
|
||||||
|
|
||||||
|
* MVP, version 0.5.0: We intend to have a working version by mid March 2024 (version 0.5, MVP)
|
||||||
|
* Stable, version 1.0.0 will come later in December 2024
|
||||||
|
|
||||||
|
MVP stands for _Minimum Viable Product_
|
||||||
|
|
||||||
|
## Version 0.5 or MVP (early 2024)
|
||||||
|
|
||||||
|
Version 0.5 includes the engine, javascript and nodejs bindings and a web application
|
||||||
|
|
||||||
|
Features of the engine include:
|
||||||
|
|
||||||
|
* Read and write xlsx files
|
||||||
|
* API to set and read values from cells
|
||||||
|
* Implemented 192 Excel functions
|
||||||
|
* Time functions with timezones
|
||||||
|
* Prepared for i18n but will only support English
|
||||||
|
* Wide test coverage
|
||||||
|
|
||||||
|
UI features of the web application (backed by the engine):
|
||||||
|
|
||||||
|
* Enter values and formulas. Browse mode
|
||||||
|
* Italics, bold, underline, horizontal alignment
|
||||||
|
* Number formatting
|
||||||
|
* Add/remove/rename sheets
|
||||||
|
* Copy/Paste extend values
|
||||||
|
* Keyboard navigation
|
||||||
|
* Delete/Add rows and columns
|
||||||
|
* Resize rows and columns
|
||||||
|
* Correct scrolling and navigation
|
||||||
|
|
||||||
|
## Version 1.0 or Stable (December 2024)
|
||||||
|
|
||||||
|
Minor milestones in the ROADMAD for version 1.0.0 (engine and UI):
|
||||||
|
|
||||||
|
* Implementation of arrays and array formulas
|
||||||
|
* Formula documentation and context help
|
||||||
|
* Merge cells
|
||||||
|
* Pivot tables
|
||||||
|
* Define name manager (mostly UI)
|
||||||
|
* Update main evaluation algorithm with a support graph
|
||||||
|
* Dynamic arrays (SORT, UNIQUE, ..)
|
||||||
|
* Full i18n support with different locales and languages
|
||||||
|
* Python bindings
|
||||||
|
* Full test coverage
|
||||||
|
|
||||||
# Early testing
|
# Early testing
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ chrono = "0.4"
|
|||||||
chrono-tz = "0.7.0"
|
chrono-tz = "0.7.0"
|
||||||
regex = "1.0"
|
regex = "1.0"
|
||||||
once_cell = "1.16.0"
|
once_cell = "1.16.0"
|
||||||
bincode = "=2.0.0-rc.3"
|
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
js-sys = { version = "0.3.60" }
|
js-sys = { version = "0.3.60" }
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use bincode::{Decode, Encode};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||||
|
|
||||||
@@ -81,7 +80,7 @@ impl fmt::Display for OpProduct {
|
|||||||
/// * "#ERROR!" means there was an error processing the formula (for instance "=A1+")
|
/// * "#ERROR!" means there was an error processing the formula (for instance "=A1+")
|
||||||
/// * "#N/IMPL!" means the formula or feature in Excel but has not been implemented in IronCalc
|
/// * "#N/IMPL!" means the formula or feature in Excel but has not been implemented in IronCalc
|
||||||
/// Note that they are serialized/deserialized by index
|
/// Note that they are serialized/deserialized by index
|
||||||
#[derive(Serialize_repr, Deserialize_repr, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize_repr, Deserialize_repr, Debug, PartialEq, Eq, Clone)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
REF,
|
REF,
|
||||||
|
|||||||
12
base/src/garbage_collector.rs
Normal file
12
base/src/garbage_collector.rs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
use crate::model::Model;
|
||||||
|
|
||||||
|
// The gc (Garbage Collector) cleans up leftover elements in the workbook:
|
||||||
|
// * Strings that are no longe reachable
|
||||||
|
// * Styles that are no longer reachable
|
||||||
|
// * ...
|
||||||
|
|
||||||
|
impl Model {
|
||||||
|
pub(crate) fn gc(&mut self) -> Result<(), String> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,6 +50,7 @@ mod implicit_intersection;
|
|||||||
mod units;
|
mod units;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod workbook;
|
mod workbook;
|
||||||
|
mod garbage_collector;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
//! IronCalc is row first. A cell is referenced by (`sheet`, `row`, `column`)
|
//! IronCalc is row first. A cell is referenced by (`sheet`, `row`, `column`)
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use bincode::config;
|
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -1719,12 +1718,6 @@ impl Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// bin
|
|
||||||
pub fn to_binary_str(&self) -> Vec<u8> {
|
|
||||||
let config = config::standard();
|
|
||||||
bincode::encode_to_vec(&self.workbook, config).expect("")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns markup representation of the given `sheet`.
|
/// Returns markup representation of the given `sheet`.
|
||||||
pub fn sheet_markup(&self, sheet: u32) -> Result<String, String> {
|
pub fn sheet_markup(&self, sheet: u32) -> Result<String, String> {
|
||||||
let worksheet = self.workbook.worksheet(sheet)?;
|
let worksheet = self.workbook.worksheet(sheet)?;
|
||||||
|
|||||||
@@ -53,3 +53,4 @@ mod test_frozen_rows_and_columns;
|
|||||||
mod test_get_cell_content;
|
mod test_get_cell_content;
|
||||||
mod test_percentage;
|
mod test_percentage;
|
||||||
mod test_today;
|
mod test_today;
|
||||||
|
mod test_gc;
|
||||||
|
|||||||
22
base/src/test/test_gc.rs
Normal file
22
base/src/test/test_gc.rs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#![allow(clippy::unwrap_used)]
|
||||||
|
|
||||||
|
use crate::test::util::new_empty_model;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty_model() {
|
||||||
|
let mut model = new_empty_model();
|
||||||
|
// set a string
|
||||||
|
model._set("A1", "Hello");
|
||||||
|
assert_eq!(model.shared_strings.len(), 1);
|
||||||
|
// calling the gc doesn't do anything
|
||||||
|
model.gc().unwrap();
|
||||||
|
assert_eq!(model.shared_strings.len(), 1);
|
||||||
|
|
||||||
|
// If we delete the cell the string is still in the list
|
||||||
|
model.delete_cell(0, 1, 1).unwrap();
|
||||||
|
assert_eq!(model.shared_strings.len(), 1);
|
||||||
|
|
||||||
|
// after the gc the string is no longer present
|
||||||
|
model.gc().unwrap();
|
||||||
|
assert_eq!(model.shared_strings.len(), 0);
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
use bincode::{Decode, Encode};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::HashMap, fmt::Display};
|
use std::{collections::HashMap, fmt::Display};
|
||||||
|
|
||||||
@@ -34,7 +33,7 @@ fn hashmap_is_empty(h: &HashMap<String, Table>) -> bool {
|
|||||||
h.values().len() == 0
|
h.values().len() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct Metadata {
|
pub struct Metadata {
|
||||||
pub application: String,
|
pub application: String,
|
||||||
pub app_version: String,
|
pub app_version: String,
|
||||||
@@ -44,13 +43,13 @@ pub struct Metadata {
|
|||||||
pub last_modified: String, //"2020-11-20T16:24:35"
|
pub last_modified: String, //"2020-11-20T16:24:35"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct WorkbookSettings {
|
pub struct WorkbookSettings {
|
||||||
pub tz: String,
|
pub tz: String,
|
||||||
pub locale: String,
|
pub locale: String,
|
||||||
}
|
}
|
||||||
/// An internal representation of an IronCalc Workbook
|
/// An internal representation of an IronCalc Workbook
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Workbook {
|
pub struct Workbook {
|
||||||
pub shared_strings: Vec<String>,
|
pub shared_strings: Vec<String>,
|
||||||
@@ -66,7 +65,7 @@ pub struct Workbook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A defined name. The `sheet_id` is the sheet index in case the name is local
|
/// A defined name. The `sheet_id` is the sheet index in case the name is local
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct DefinedName {
|
pub struct DefinedName {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub formula: String,
|
pub formula: String,
|
||||||
@@ -80,7 +79,7 @@ pub struct DefinedName {
|
|||||||
/// * state:
|
/// * state:
|
||||||
/// 18.18.68 ST_SheetState (Sheet Visibility Types)
|
/// 18.18.68 ST_SheetState (Sheet Visibility Types)
|
||||||
/// hidden, veryHidden, visible
|
/// hidden, veryHidden, visible
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum SheetState {
|
pub enum SheetState {
|
||||||
Visible,
|
Visible,
|
||||||
@@ -99,7 +98,7 @@ impl Display for SheetState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Internal representation of a worksheet Excel object
|
/// Internal representation of a worksheet Excel object
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||||
pub struct Worksheet {
|
pub struct Worksheet {
|
||||||
pub dimension: String,
|
pub dimension: String,
|
||||||
pub cols: Vec<Col>,
|
pub cols: Vec<Col>,
|
||||||
@@ -126,7 +125,7 @@ pub struct Worksheet {
|
|||||||
pub type SheetData = HashMap<i32, HashMap<i32, Cell>>;
|
pub type SheetData = HashMap<i32, HashMap<i32, Cell>>;
|
||||||
|
|
||||||
// ECMA-376-1:2016 section 18.3.1.73
|
// ECMA-376-1:2016 section 18.3.1.73
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||||
pub struct Row {
|
pub struct Row {
|
||||||
/// Row index
|
/// Row index
|
||||||
pub r: i32,
|
pub r: i32,
|
||||||
@@ -140,7 +139,7 @@ pub struct Row {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ECMA-376-1:2016 section 18.3.1.13
|
// ECMA-376-1:2016 section 18.3.1.13
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||||
pub struct Col {
|
pub struct Col {
|
||||||
// Column definitions are defined on ranges, unlike rows which store unique, per-row entries.
|
// Column definitions are defined on ranges, unlike rows which store unique, per-row entries.
|
||||||
/// First column affected by this record. Settings apply to column in \[min, max\] range.
|
/// First column affected by this record. Settings apply to column in \[min, max\] range.
|
||||||
@@ -165,7 +164,7 @@ pub enum CellType {
|
|||||||
CompoundData = 128,
|
CompoundData = 128,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||||
#[serde(tag = "t", deny_unknown_fields)]
|
#[serde(tag = "t", deny_unknown_fields)]
|
||||||
pub enum Cell {
|
pub enum Cell {
|
||||||
#[serde(rename = "empty")]
|
#[serde(rename = "empty")]
|
||||||
@@ -209,7 +208,7 @@ impl Default for Cell {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct Comment {
|
pub struct Comment {
|
||||||
pub text: String,
|
pub text: String,
|
||||||
pub author_name: String,
|
pub author_name: String,
|
||||||
@@ -219,7 +218,7 @@ pub struct Comment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ECMA-376-1:2016 section 18.5.1.2
|
// ECMA-376-1:2016 section 18.5.1.2
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub display_name: String,
|
pub display_name: String,
|
||||||
@@ -242,7 +241,7 @@ pub struct Table {
|
|||||||
|
|
||||||
// totals_row_label vs totals_row_function might be mutually exclusive. Use an enum?
|
// totals_row_label vs totals_row_function might be mutually exclusive. Use an enum?
|
||||||
// the totals_row_function is an enum not String methinks
|
// the totals_row_function is an enum not String methinks
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct TableColumn {
|
pub struct TableColumn {
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -272,7 +271,7 @@ impl Default for TableColumn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone, Default)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)]
|
||||||
pub struct TableStyleInfo {
|
pub struct TableStyleInfo {
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
@@ -290,7 +289,7 @@ pub struct TableStyleInfo {
|
|||||||
pub show_column_stripes: bool,
|
pub show_column_stripes: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct Styles {
|
pub struct Styles {
|
||||||
pub num_fmts: Vec<NumFmt>,
|
pub num_fmts: Vec<NumFmt>,
|
||||||
pub fonts: Vec<Font>,
|
pub fonts: Vec<Font>,
|
||||||
@@ -315,7 +314,7 @@ impl Default for Styles {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct Style {
|
pub struct Style {
|
||||||
pub alignment: Option<Alignment>,
|
pub alignment: Option<Alignment>,
|
||||||
pub num_fmt: String,
|
pub num_fmt: String,
|
||||||
@@ -325,7 +324,7 @@ pub struct Style {
|
|||||||
pub quote_prefix: bool,
|
pub quote_prefix: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct NumFmt {
|
pub struct NumFmt {
|
||||||
pub num_fmt_id: i32,
|
pub num_fmt_id: i32,
|
||||||
pub format_code: String,
|
pub format_code: String,
|
||||||
@@ -343,7 +342,7 @@ impl Default for NumFmt {
|
|||||||
// ST_FontScheme simple type (§18.18.33).
|
// ST_FontScheme simple type (§18.18.33).
|
||||||
// Usually major fonts are used for styles like headings,
|
// Usually major fonts are used for styles like headings,
|
||||||
// and minor fonts are used for body and paragraph text.
|
// and minor fonts are used for body and paragraph text.
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub enum FontScheme {
|
pub enum FontScheme {
|
||||||
@@ -363,7 +362,7 @@ impl Display for FontScheme {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct Font {
|
pub struct Font {
|
||||||
#[serde(default = "default_as_false")]
|
#[serde(default = "default_as_false")]
|
||||||
#[serde(skip_serializing_if = "is_false")]
|
#[serde(skip_serializing_if = "is_false")]
|
||||||
@@ -406,7 +405,7 @@ impl Default for Font {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Maybe use an enum for the pattern_type values here?
|
// TODO: Maybe use an enum for the pattern_type values here?
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct Fill {
|
pub struct Fill {
|
||||||
pub pattern_type: String,
|
pub pattern_type: String,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
@@ -425,7 +424,7 @@ impl Default for Fill {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum HorizontalAlignment {
|
pub enum HorizontalAlignment {
|
||||||
Center,
|
Center,
|
||||||
@@ -467,7 +466,7 @@ impl Display for HorizontalAlignment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum VerticalAlignment {
|
pub enum VerticalAlignment {
|
||||||
Bottom,
|
Bottom,
|
||||||
@@ -502,7 +501,7 @@ impl Display for VerticalAlignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 1762
|
// 1762
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone, Default)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)]
|
||||||
pub struct Alignment {
|
pub struct Alignment {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
#[serde(skip_serializing_if = "HorizontalAlignment::is_default")]
|
#[serde(skip_serializing_if = "HorizontalAlignment::is_default")]
|
||||||
@@ -515,7 +514,7 @@ pub struct Alignment {
|
|||||||
pub wrap_text: bool,
|
pub wrap_text: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct CellStyleXfs {
|
pub struct CellStyleXfs {
|
||||||
pub num_fmt_id: i32,
|
pub num_fmt_id: i32,
|
||||||
pub font_id: i32,
|
pub font_id: i32,
|
||||||
@@ -558,7 +557,7 @@ impl Default for CellStyleXfs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone, Default)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)]
|
||||||
pub struct CellXfs {
|
pub struct CellXfs {
|
||||||
pub xf_id: i32,
|
pub xf_id: i32,
|
||||||
pub num_fmt_id: i32,
|
pub num_fmt_id: i32,
|
||||||
@@ -590,7 +589,7 @@ pub struct CellXfs {
|
|||||||
pub alignment: Option<Alignment>,
|
pub alignment: Option<Alignment>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct CellStyles {
|
pub struct CellStyles {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub xf_id: i32,
|
pub xf_id: i32,
|
||||||
@@ -607,7 +606,7 @@ impl Default for CellStyles {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum BorderStyle {
|
pub enum BorderStyle {
|
||||||
Thin,
|
Thin,
|
||||||
@@ -637,13 +636,13 @@ impl Display for BorderStyle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct BorderItem {
|
pub struct BorderItem {
|
||||||
pub style: BorderStyle,
|
pub style: BorderStyle,
|
||||||
pub color: Option<String>,
|
pub color: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq, Eq, Clone, Default)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)]
|
||||||
pub struct Border {
|
pub struct Border {
|
||||||
#[serde(default = "default_as_false")]
|
#[serde(default = "default_as_false")]
|
||||||
#[serde(skip_serializing_if = "is_false")]
|
#[serde(skip_serializing_if = "is_false")]
|
||||||
@@ -665,7 +664,7 @@ pub struct Border {
|
|||||||
|
|
||||||
/// Information need to show a sheet tab in the UI
|
/// Information need to show a sheet tab in the UI
|
||||||
/// The color is serialized only if it is not Color::None
|
/// The color is serialized only if it is not Color::None
|
||||||
#[derive(Serialize, Deserialize, Decode, Encode, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
pub struct SheetInfo {
|
pub struct SheetInfo {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub state: String,
|
pub state: String,
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ thiserror = "1.0"
|
|||||||
ironcalc_base = { path = "../base", version = "0.1.0" }
|
ironcalc_base = { path = "../base", version = "0.1.0" }
|
||||||
itertools = "0.10.5"
|
itertools = "0.10.5"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
bincode = "=2.0.0-rc.3"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
uuid = { version = "1.2.2", features = ["serde", "v4"] }
|
uuid = { version = "1.2.2", features = ["serde", "v4"] }
|
||||||
@@ -35,8 +34,3 @@ path = "src/lib.rs"
|
|||||||
[[bin]]
|
[[bin]]
|
||||||
name = "test"
|
name = "test"
|
||||||
path = "src/bin/test.rs"
|
path = "src/bin/test.rs"
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "bench"
|
|
||||||
path = "src/bin/bench.rs"
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
use std::{fs, io::Write, time::Instant};
|
|
||||||
|
|
||||||
use bincode::config;
|
|
||||||
use ironcalc::import::load_model_from_xlsx;
|
|
||||||
use ironcalc_base::{types::Workbook, model::Model};
|
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let args: Vec<_> = std::env::args().collect();
|
|
||||||
if args.len() != 2 {
|
|
||||||
panic!("Usage: {} <file.xlsx>", args[0]);
|
|
||||||
}
|
|
||||||
let file_name = &args[1];
|
|
||||||
let now = Instant::now();
|
|
||||||
let mut model = load_model_from_xlsx(file_name, "en", "UTC").unwrap();
|
|
||||||
let elapsed_time = now.elapsed();
|
|
||||||
println!("Loaded model from xlsx: {:?}", elapsed_time);
|
|
||||||
model.evaluate();
|
|
||||||
let now = Instant::now();
|
|
||||||
let s = model.to_json_str();
|
|
||||||
let elapsed_time = now.elapsed();
|
|
||||||
println!("Stringify json: {:?}", elapsed_time);
|
|
||||||
{
|
|
||||||
let now = Instant::now();
|
|
||||||
let decoded : Workbook = serde_json::from_str(&s).unwrap();
|
|
||||||
let elapsed_time = now.elapsed();
|
|
||||||
println!("Parse from json: {:?} and name {}", elapsed_time, decoded.name);
|
|
||||||
}
|
|
||||||
let file_name_json = format!("{}.json", file_name);
|
|
||||||
let file_path = std::path::Path::new(&file_name_json);
|
|
||||||
let mut file = fs::File::create(file_path).unwrap();
|
|
||||||
file.write_all(s.as_bytes()).unwrap();
|
|
||||||
let now = Instant::now();
|
|
||||||
let s = model.to_binary_str();
|
|
||||||
let elapsed_time = now.elapsed();
|
|
||||||
println!("stringify to binary: {:?}", elapsed_time);
|
|
||||||
{
|
|
||||||
let config = config::standard();
|
|
||||||
let now = Instant::now();
|
|
||||||
let (decoded, _): (Workbook, usize) = bincode::decode_from_slice(&s[..], config).unwrap();
|
|
||||||
let elapsed_time = now.elapsed();
|
|
||||||
println!("Parse from binary: {:?} and {}", elapsed_time, decoded.name);
|
|
||||||
}
|
|
||||||
let file_name_binary = format!("{}.binary", file_name);
|
|
||||||
let file_path = std::path::Path::new(&file_name_binary);
|
|
||||||
let mut file = fs::File::create(file_path).unwrap();
|
|
||||||
file.write_all(&s).unwrap();
|
|
||||||
{
|
|
||||||
let config = config::standard();
|
|
||||||
let now = Instant::now();
|
|
||||||
let s = &fs::read(file_name_binary).unwrap();
|
|
||||||
let (decoded, _): (Workbook, usize) = bincode::decode_from_slice(&s[..], config).unwrap();
|
|
||||||
let model = Model::from_workbook(decoded).unwrap();
|
|
||||||
let elapsed_time = now.elapsed();
|
|
||||||
println!("Loaded from binary file: {:?} and {}", elapsed_time, model.workbook.name);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user