diff --git a/.gitignore b/.gitignore index d01bd1a..20e8ea8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1,2 @@ -# Generated by Cargo -# will have compiled files and executables -debug/ -target/ - -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock - -# These are backup files generated by rustfmt -**/*.rs.bk - -# MSVC Windows builds of rustc generate these, which store debugging information -*.pdb - -# RustRover -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ \ No newline at end of file +/target +test.daletpack diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..ebbe47e --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,516 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cc" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "dalet" +version = "1.0.0-pre4" +dependencies = [ + "bincode", + "clap", + "flate2", + "num_enum", + "rmp-serde", + "serde", + "serde_repr", + "zstd", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_repr" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa556e971e7b568dc775c136fc9de8c779b1c2fc3a63defaafadffdbd3181afa" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.12+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a4e40c320c3cb459d9a9ff6de98cff88f4751ee9275d140e2be94a2b74e4c13" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..00f7017 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "dalet" +version = "1.0.0-pre4" +edition = "2021" +authors = ["artegoser"] +license = "MIT" +description = "Dalet implementation in Rust" +repository = "https://github.com/txtdot/dalet" +homepage = "https://github.com/TxtDot/dalet/tree/main/libs/rust" +readme = "./README.md" +keywords = ["dalet"] +categories = ["compression", "compilers", "encoding"] + +[dependencies] +clap = { version = "4.5.13", features = ["derive"] } +num_enum = "0.7.3" +serde = { version = "1.0", features = ["derive"] } +serde_repr = "0.1" +zstd = "0.13.2" + +[dev-dependencies] +rmp-serde = { version = "1.3.0" } +bincode = { version = "1.3.3" } +flate2 = "1.0" + + +[features] +default = ["types", "daletpack"] +types = [] +daletpack = ["types"] diff --git a/src/abstractions.rs b/src/abstractions.rs new file mode 100644 index 0000000..deacb19 --- /dev/null +++ b/src/abstractions.rs @@ -0,0 +1,257 @@ +use num_enum::TryFromPrimitive; + +use crate::daletl::{self, t_new, Tid}; + +const NB: daletl::Body = daletl::Body::Null; +const NA: daletl::Argument = daletl::Argument::Null; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Tag { + El(NotNullBody), + H(String, HeadingLevel), + P(NotNullBody), + Br, + Ul(Vec), + Ol(Vec), + Row(Vec, AlignArgument), + Link(Body, String), + Navlink(Body, String), + Btn(Body, String), + Navbtn(Body, String), + Img(String), + Table(Vec), + Tcol(Vec), + Tpcol(Vec), + Hr, + B(String), + I(String), + Bq(NotNullBody), + Footlnk(TextOrNumberArgument), + Footn(String, TextOrNumberArgument), + A(TextOrNumberArgument), + S(String), + Sup(String), + Sub(String), + Disc(NotNullBody), + Bl(NotNullBody, AlignArgument), + Carousel(Vec), + Code(String, TextOrNullArgument), +} + +pub trait ToDaletl { + fn to_daletl(self) -> Vec; +} + +pub trait ToDaletlTag { + fn to_daletl_tag(self) -> daletl::Tag; +} + +impl ToDaletlTag for Tag { + fn to_daletl_tag(self) -> daletl::Tag { + match self { + Tag::El(b) => t_new(Tid::El, b.to_daletl_body(), NA), + Tag::H(b, a) => t_new(Tid::H, b.to_daletl_body(), a.to_daletl_argument()), + Tag::P(b) => t_new(Tid::P, b.to_daletl_body(), NA), + Tag::Br => t_new(Tid::Br, NB, NA), + Tag::Ul(b) => t_new(Tid::Ul, b.to_daletl_body(), NA), + Tag::Ol(b) => t_new(Tid::Ol, b.to_daletl_body(), NA), + Tag::Row(b, a) => t_new(Tid::Row, b.to_daletl_body(), a.to_daletl_argument()), + Tag::Link(b, a) => t_new(Tid::Link, b.to_daletl_body(), a.to_daletl_argument()), + Tag::Navlink(b, a) => t_new(Tid::Navlink, b.to_daletl_body(), a.to_daletl_argument()), + Tag::Btn(b, a) => t_new(Tid::Btn, b.to_daletl_body(), a.to_daletl_argument()), + Tag::Navbtn(b, a) => t_new(Tid::Navbtn, b.to_daletl_body(), a.to_daletl_argument()), + Tag::Img(a) => t_new(Tid::Img, NB, a.to_daletl_argument()), + Tag::Table(b) => t_new(Tid::Table, b.to_daletl_body(), NA), + Tag::Tcol(b) => t_new(Tid::Tcol, b.to_daletl_body(), NA), + Tag::Tpcol(b) => t_new(Tid::Tpcol, b.to_daletl_body(), NA), + Tag::Hr => t_new(Tid::Hr, NB, NA), + Tag::B(b) => t_new(Tid::B, b.to_daletl_body(), NA), + Tag::I(b) => t_new(Tid::I, b.to_daletl_body(), NA), + Tag::Bq(b) => t_new(Tid::Bq, b.to_daletl_body(), NA), + Tag::Footlnk(a) => t_new(Tid::Footlnk, NB, a.to_daletl_argument()), + Tag::Footn(b, a) => t_new(Tid::Footn, b.to_daletl_body(), a.to_daletl_argument()), + Tag::A(a) => t_new(Tid::A, NB, a.to_daletl_argument()), + Tag::S(b) => t_new(Tid::S, b.to_daletl_body(), NA), + Tag::Sup(b) => t_new(Tid::Sup, b.to_daletl_body(), NA), + Tag::Sub(b) => t_new(Tid::Sub, b.to_daletl_body(), NA), + Tag::Disc(b) => t_new(Tid::Disc, b.to_daletl_body(), NA), + Tag::Bl(b, a) => t_new(Tid::Bl, b.to_daletl_body(), a.to_daletl_argument()), + Tag::Carousel(b) => t_new(Tid::Carousel, b.to_daletl_body(), NA), + Tag::Code(s, a) => t_new(Tid::Code, s.to_daletl_body(), a.to_daletl_argument()), + } + } +} + +pub trait ToDaletlBody { + fn to_daletl_body(self) -> daletl::Body; +} + +pub trait ToDaletlArgument { + fn to_daletl_argument(self) -> daletl::Argument; +} + +#[derive(Debug, Clone, PartialEq, Eq, TryFromPrimitive)] +#[repr(u8)] +pub enum HeadingLevel { + One = 1, + Two, + Three, + Four, + Five, + Six, +} + +impl ToDaletlArgument for HeadingLevel { + fn to_daletl_argument(self) -> daletl::Argument { + match self { + HeadingLevel::One => NA, + HeadingLevel::Two => 2u8.to_daletl_argument(), + HeadingLevel::Three => 3u8.to_daletl_argument(), + HeadingLevel::Four => 4u8.to_daletl_argument(), + HeadingLevel::Five => 5u8.to_daletl_argument(), + HeadingLevel::Six => 6u8.to_daletl_argument(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, TryFromPrimitive)] +#[repr(u8)] +pub enum AlignArgument { + Start, + Center, + End, +} + +impl ToDaletlArgument for AlignArgument { + fn to_daletl_argument(self) -> daletl::Argument { + match self { + Self::Start => NA, + Self::Center => 1u8.to_daletl_argument(), + Self::End => 2u8.to_daletl_argument(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum TextOrNumberArgument { + Text(String), + Number(u8), +} + +impl ToDaletlArgument for TextOrNumberArgument { + fn to_daletl_argument(self) -> daletl::Argument { + match self { + Self::Number(n) => n.to_daletl_argument(), + Self::Text(s) => s.to_daletl_argument(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum TextOrNullArgument { + Text(String), + Null, +} + +impl ToDaletlArgument for TextOrNullArgument { + fn to_daletl_argument(self) -> daletl::Argument { + match self { + Self::Text(s) => s.to_daletl_argument(), + Self::Null => NA, + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Body { + Text(String), + Tags(Vec), + Null, +} + +impl ToDaletlBody for Body { + fn to_daletl_body(self) -> daletl::Body { + match self { + Body::Null => NB, + Body::Tags(v) => v.to_daletl_body(), + Body::Text(v) => v.to_daletl_body(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Argument { + Text(String), + Number(u8), + Null, +} + +impl ToDaletlArgument for Argument { + fn to_daletl_argument(self) -> daletl::Argument { + match self { + Argument::Null => NA, + Argument::Number(v) => v.to_daletl_argument(), + Argument::Text(v) => v.to_daletl_argument(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum NotNullArgument { + Text(String), + Number(u8), +} + +impl ToDaletlArgument for NotNullArgument { + fn to_daletl_argument(self) -> daletl::Argument { + match self { + NotNullArgument::Number(v) => v.to_daletl_argument(), + NotNullArgument::Text(v) => v.to_daletl_argument(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum NotNullBody { + Text(String), + Tags(Vec), +} + +impl ToDaletlBody for NotNullBody { + fn to_daletl_body(self) -> daletl::Body { + match self { + NotNullBody::Text(v) => v.to_daletl_body(), + NotNullBody::Tags(v) => v.to_daletl_body(), + } + } +} + +impl ToDaletlBody for Vec { + fn to_daletl_body(self) -> daletl::Body { + daletl::Body::Tags(self.to_daletl()) + } +} + +impl ToDaletl for Vec { + fn to_daletl(self) -> Vec { + self.into_iter().map(|tag| tag.to_daletl_tag()).collect() + } +} + +impl ToDaletlBody for String { + fn to_daletl_body(self) -> daletl::Body { + daletl::Body::Text(self) + } +} + +impl ToDaletlArgument for String { + fn to_daletl_argument(self) -> daletl::Argument { + daletl::Argument::Text(self) + } +} + +impl ToDaletlArgument for u8 { + fn to_daletl_argument(self) -> daletl::Argument { + daletl::Argument::Number(self) + } +} diff --git a/src/commands.rs b/src/commands.rs new file mode 100644 index 0000000..5361b04 --- /dev/null +++ b/src/commands.rs @@ -0,0 +1,13 @@ +use clap::{Parser, Subcommand}; + +#[derive(Debug, Parser)] +#[command(name = "cimengine", bin_name = "cimengine")] +#[command(about = "CIMEngine build tools")] +pub struct Cli { + #[command(subcommand)] + pub cmd: Commands, +} + +#[derive(Debug, Subcommand)] +#[clap(author, version, about)] +pub enum Commands {} diff --git a/src/daletl.rs b/src/daletl.rs new file mode 100644 index 0000000..bde9dc8 --- /dev/null +++ b/src/daletl.rs @@ -0,0 +1,95 @@ +use serde::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; + +use num_enum::TryFromPrimitive; + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +pub struct Tag { + pub id: Tid, + pub body: Body, + pub argument: Argument, +} + +impl Tag { + #[inline] + pub fn new(id: Tid, body: Body, argument: Argument) -> Tag { + Tag { id, body, argument } + } +} + +pub fn t_new(id: Tid, body: Body, argument: Argument) -> Tag { + Tag::new(id, body, argument) +} + +pub trait IsNull { + fn is_null(&self) -> bool; +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[serde(untagged)] +pub enum Body { + Text(String), + Tags(Vec), + Null, +} + +impl IsNull for Body { + fn is_null(&self) -> bool { + match self { + Self::Null => true, + _ => false, + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[serde(untagged)] +pub enum Argument { + Text(String), + Number(u8), + Null, +} + +impl IsNull for Argument { + fn is_null(&self) -> bool { + match self { + Self::Null => true, + _ => false, + } + } +} + +#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, PartialEq, Eq, TryFromPrimitive, Copy)] +#[repr(u8)] +/// Tag Id +pub enum Tid { + El, + H, + P, + Br, + Ul, + Ol, + Row, + Link, + Navlink, + Btn, + Navbtn, + Img, + Table, + Tcol, + Tpcol, + Hr, + B, + I, + Bq, + Footlnk, + Footn, + A, + S, + Sup, + Sub, + Disc, + Bl, + Carousel, + Code, +} diff --git a/src/daletpack/encode.rs b/src/daletpack/encode.rs new file mode 100644 index 0000000..df27c2e --- /dev/null +++ b/src/daletpack/encode.rs @@ -0,0 +1,110 @@ +use crate::daletl::{Argument, Body, IsNull, Tag, Tid}; + +use super::{DaletPackError, TypeId}; + +pub fn encode(root: &Vec) -> Result, DaletPackError> { + Ok(zstd::bulk::compress(&encode_no_compress(root)?, 5) + .map_err(|_| DaletPackError::ZstdCompressError)?) +} + +pub fn encode_no_compress(root: &Vec) -> Result, DaletPackError> { + if root.len() > 2usize.pow(32) { + return Err(DaletPackError::RootMaxSizeExceeded); + } + + let mut bv: Vec = Vec::new(); + + for tag in root { + write_tag(&mut bv, tag)?; + } + + Ok(bv) +} + +fn write_int(bv: &mut Vec, n: u8) { + bv.push(1); + bv.push(n); +} + +fn write_str(bv: &mut Vec, string: &String) -> Result<(), DaletPackError> { + let size = string.len(); + + if size > 2usize.pow(32) { + return Err(DaletPackError::StrMaxSizeExceeded); + } + + if size <= 256 { + bv.push(TypeId::Str8 as u8); + bv.push((size - 1) as u8); + } else if size <= 65536 { + bv.push(TypeId::Str16 as u8); + bv.extend(((size - 1) as u16).to_be_bytes()); + } else { + bv.push(TypeId::Str32 as u8); + bv.extend(((size - 1) as u32).to_be_bytes()); + } + + bv.extend_from_slice(string.as_bytes()); + + Ok(()) +} + +fn write_array(bv: &mut Vec, arr: &Vec) -> Result<(), DaletPackError> { + if arr.len() > 2usize.pow(32) { + return Err(DaletPackError::ArrMaxSizeExceeded); + } + + bv.push(TypeId::TagArray as u8); + + for tag in arr { + write_tag(bv, tag)?; + } + + bv.push(TypeId::TagArrayEnd as u8); + + Ok(()) +} + +fn write_tag(bv: &mut Vec, tag: &Tag) -> Result<(), DaletPackError> { + if tag.id == Tid::El { + write_tag_body(bv, &tag.body)?; + } else if tag.body.is_null() && tag.argument.is_null() { + bv.push(TypeId::TagId as u8); + bv.push(tag.id as u8); + } else if tag.argument.is_null() { + bv.push(TypeId::TagIdBody as u8); + bv.push(tag.id as u8); + write_tag_body(bv, &tag.body)?; + } else if tag.body.is_null() { + bv.push(TypeId::TagIdArgument as u8); + bv.push(tag.id as u8); + write_tag_argument(bv, &tag.argument)?; + } else { + bv.push(TypeId::TagIdBodyArgument as u8); + bv.push(tag.id as u8); + write_tag_body(bv, &tag.body)?; + write_tag_argument(bv, &tag.argument)?; + } + + Ok(()) +} + +fn write_tag_body(bv: &mut Vec, body: &Body) -> Result<(), DaletPackError> { + match body { + Body::Text(s) => write_str(bv, s)?, + Body::Tags(tags) => write_array(bv, tags)?, + Body::Null => Err(DaletPackError::WriteNullBody)?, + }; + + Ok(()) +} + +fn write_tag_argument(bv: &mut Vec, argument: &Argument) -> Result<(), DaletPackError> { + match argument { + Argument::Text(s) => write_str(bv, s)?, + Argument::Number(n) => write_int(bv, *n), + Argument::Null => Err(DaletPackError::WriteNullArgument)?, + }; + + Ok(()) +} diff --git a/src/daletpack/mod.rs b/src/daletpack/mod.rs new file mode 100644 index 0000000..ea2f18f --- /dev/null +++ b/src/daletpack/mod.rs @@ -0,0 +1,6 @@ +mod encode; +mod types; + +pub mod utils; +pub use encode::*; +pub use types::*; diff --git a/src/daletpack/types.rs b/src/daletpack/types.rs new file mode 100644 index 0000000..edd6fc0 --- /dev/null +++ b/src/daletpack/types.rs @@ -0,0 +1,27 @@ +use num_enum::TryFromPrimitive; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum DaletPackError { + StrMaxSizeExceeded, + ArrMaxSizeExceeded, + RootMaxSizeExceeded, + ZstdCompressError, + + WriteNullBody, + WriteNullArgument, +} + +#[derive(Debug, Clone, PartialEq, Eq, TryFromPrimitive, Copy)] +#[repr(u8)] +pub enum TypeId { + Int8 = 1, + Str8 = 4, + Str16, + Str32, + TagArray, + TagArrayEnd, + TagId = 12, + TagIdBody, + TagIdArgument, + TagIdBodyArgument, +} diff --git a/src/daletpack/utils.rs b/src/daletpack/utils.rs new file mode 100644 index 0000000..3d1084a --- /dev/null +++ b/src/daletpack/utils.rs @@ -0,0 +1,3 @@ +pub fn compress_zstd(data: &Vec) -> std::io::Result> { + zstd::bulk::compress(data, 22) +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..ed28b94 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,8 @@ +#[cfg(feature = "types")] +pub mod daletl; + +#[cfg(feature = "types")] +pub mod abstractions; + +#[cfg(feature = "daletpack")] +pub mod daletpack; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..7de06b0 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,3 @@ +mod commands; + +fn main() {} diff --git a/tests/bench.md b/tests/bench.md new file mode 100644 index 0000000..27e15e4 --- /dev/null +++ b/tests/bench.md @@ -0,0 +1,17 @@ +# Heading 1 +## Heading 2 +Some **bold** *italic* ~~strike~~ + +`Hello world` + +- abc +- def + - defabc + - defdef +- xyz + +Lorem ipsum [![](https://my-picture)](https://some-link) dolor sit amet consequetur adipiscing elit + +| col1 | col2 | col3 | +| ----------- | -------- | ---- | +| Never gonna | give you | up | diff --git a/tests/bench.rs b/tests/bench.rs new file mode 100644 index 0000000..399a0cb --- /dev/null +++ b/tests/bench.rs @@ -0,0 +1,115 @@ +use dalet::{ + abstractions::{Body, HeadingLevel, NotNullBody, Tag, TextOrNullArgument, ToDaletl}, + daletpack::*, +}; +use flate2::Compression; +use std::io::{read_to_string, Write}; + +#[macro_export] +macro_rules! iprint { + ($name:expr, $func:expr) => {{ + let start = std::time::Instant::now(); + let result = $func; + let elapsed = start.elapsed(); + println!("{} ({:#?}): {} bytes", $name, elapsed, result.len()); + + result + }}; +} + +pub fn compress_deflate(data: &Vec) -> std::io::Result> { + let mut c = flate2::write::DeflateEncoder::new(Vec::new(), Compression::default()); + c.write(data)?; + c.finish() +} + +pub fn compress_zlib(data: &Vec) -> std::io::Result> { + let mut c = flate2::write::ZlibEncoder::new(Vec::new(), Compression::default()); + c.write(data)?; + c.finish() +} + +#[test] +fn bench() { + let page: Vec = vec![ + Tag::H("I am heading".to_owned(), HeadingLevel::One), + Tag::H("Heading 2".to_owned(), HeadingLevel::Two), + Tag::El(NotNullBody::Tags(vec![ + Tag::El(NotNullBody::Text("Some ".to_owned())), + Tag::B("bold".to_owned()), + Tag::I("italic".to_owned()), + Tag::S("strike".to_owned()), + ])), + Tag::Br, + Tag::Code("Hello world".to_owned(), TextOrNullArgument::Null), + Tag::Br, + Tag::Ol(vec![ + Tag::El(NotNullBody::Text("abc".to_owned())), + Tag::El(NotNullBody::Tags(vec![ + Tag::El(NotNullBody::Text("def".to_owned())), + Tag::Ol(vec![ + Tag::El(NotNullBody::Text("defabc".to_owned())), + Tag::El(NotNullBody::Text("defdef".to_owned())), + ]), + ])), + Tag::El(NotNullBody::Text("xyz".to_owned())), + ]), + Tag::Br, + Tag::El(NotNullBody::Tags(vec![ + Tag::El(NotNullBody::Text("Lorem ipsum ".to_owned())), + Tag::Link( + Body::Tags(vec![Tag::Img("https://my-picture".to_owned())]), + "https://some-link".to_owned(), + ), + Tag::El(NotNullBody::Text( + " dolor sit amet consequetur adipiscing elit".to_owned(), + )), + ])), + Tag::Table(vec![ + Tag::Tpcol(vec![ + Tag::El(NotNullBody::Text("Col 1".to_owned())), + Tag::El(NotNullBody::Text("Col 2".to_owned())), + Tag::El(NotNullBody::Text("Col 3".to_owned())), + ]), + Tag::Tcol(vec![ + Tag::El(NotNullBody::Text("Never gonna".to_owned())), + Tag::El(NotNullBody::Text("give you".to_owned())), + Tag::El(NotNullBody::Text("up".to_owned())), + ]), + ]), + ]; + + let dalet_page = page.to_daletl(); + + let markdown = iprint!("Markdown", include_str!("./bench.md").as_bytes().to_vec()); + let daletpack = iprint!("Daletpack", encode_no_compress(&dalet_page).unwrap()); + let messagepack = iprint!("Messagepack", rmp_serde::to_vec(&dalet_page).unwrap()); + let bincode = iprint!("Bincode", bincode::serialize(&dalet_page).unwrap()); + + println!(); + + iprint!("Markdown zstd", utils::compress_zstd(&markdown).unwrap()); + iprint!("Daletpack zstd", utils::compress_zstd(&daletpack).unwrap()); + iprint!( + "Messagepack zstd", + utils::compress_zstd(&messagepack).unwrap() + ); + iprint!("Bincode zstd", utils::compress_zstd(&bincode).unwrap()); + + println!(); + + iprint!("Markdown Zlib", compress_zlib(&markdown).unwrap()); + iprint!("Daletpack Zlib", compress_zlib(&daletpack).unwrap()); + iprint!("Messagepack Zlib", compress_zlib(&messagepack).unwrap()); + iprint!("Bincode Zlib", compress_zlib(&bincode).unwrap()); + + println!(); + + iprint!("Markdown deflate", compress_deflate(&markdown).unwrap()); + iprint!("Daletpack deflate", compress_deflate(&daletpack).unwrap()); + iprint!( + "Messagepack deflate", + compress_deflate(&messagepack).unwrap() + ); + iprint!("Bincode deflate", compress_deflate(&bincode).unwrap()); +}