diff --git a/src/Rust/.gitignore b/src/Rust/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ea8c4bf7f35f6f77f75d92ad8ce8349f6e81ddba --- /dev/null +++ b/src/Rust/.gitignore @@ -0,0 +1 @@ +/target diff --git a/src/Rust/Cargo.lock b/src/Rust/Cargo.lock index cd52f7b46b829d6487fc2b226cbe1a8c12a6c663..b0f1d2f5afbda940ff3c2410e16e37e1e932624e 100644 --- a/src/Rust/Cargo.lock +++ b/src/Rust/Cargo.lock @@ -52,9 +52,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.1.14" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "906f7fe1da4185b7a282b2bc90172a496f9def1aca4545fe7526810741591e14" +checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3" dependencies = [ "clap_builder", "clap_derive", @@ -63,9 +63,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.1.14" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "351f9ad9688141ed83dfd8f5fb998a06225ef444b48ff4dc43de6d409b7fd10b" +checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f" dependencies = [ "bitflags", "clap_lex", @@ -75,30 +75,30 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.1.6" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40d3120a421cd111c43f1a6c7d0dd83bb6aaa0659c164468a1654014632a5ec6" +checksum = "01c22dcfb410883764b29953103d9ef7bb8fe21b3fa1158bc99986c2067294bd" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.1.14" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81d7dc0031c3a59a04fc2ba395c8e2dd463cba1859275f065d225f6122221b45" +checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.13", ] [[package]] name = "clap_lex" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f0807fb6f644c83f3e4ec014fec9858c1c8b26a7db8eb5f0bde5817df9c1df7" +checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" [[package]] name = "clap_mangen" @@ -129,13 +129,13 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "errno" -version = "0.2.8" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" dependencies = [ "errno-dragonfly", "libc", - "winapi", + "windows-sys 0.45.0", ] [[package]] @@ -194,7 +194,7 @@ checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" dependencies = [ "hermit-abi", "libc", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -220,9 +220,9 @@ checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" [[package]] name = "log" @@ -316,6 +316,12 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +[[package]] +name = "paste" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" + [[package]] name = "pkg-config" version = "0.3.26" @@ -348,9 +354,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.54" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -395,16 +401,16 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.36.11" +version = "0.37.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e" +checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -430,9 +436,9 @@ dependencies = [ [[package]] name = "scc" -version = "1.4.1" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a83e3a5d0ddb38f854c69b8387fda1ffb87bb845b88928c66653bed16fccd11" +checksum = "9bb666a705482e987d4bbd8bb7b0a07438ecfde629044176f0a571605c03e22a" [[package]] name = "scopeguard" @@ -486,9 +492,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.11" +version = "2.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e3787bb71465627110e7d87ed4faaa36c1f61042ee67badb9e2ef173accc40" +checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" dependencies = [ "proc-macro2", "quote", @@ -497,12 +503,12 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9afddd2cec1c0909f06b00ef33f94ab2cc0578c4a610aa208ddfec8aa2b43a" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" dependencies = [ "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -522,7 +528,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.13", ] [[package]] @@ -599,6 +605,7 @@ dependencies = [ "log", "scc", "thiserror", + "vvs_procmacro", ] [[package]] @@ -623,11 +630,21 @@ version = "0.4.0" dependencies = [ "log", "mlua", + "paste", "thiserror", "toml", "vvs_ass", ] +[[package]] +name = "vvs_procmacro" +version = "0.4.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.13", +] + [[package]] name = "vvs_repl" version = "0.4.0" @@ -666,7 +683,16 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", ] [[package]] @@ -675,13 +701,28 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] [[package]] @@ -690,42 +731,84 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + [[package]] name = "windows_i686_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + [[package]] name = "windows_i686_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + [[package]] name = "winnow" version = "0.4.1" diff --git a/src/Rust/Cargo.toml b/src/Rust/Cargo.toml index c2fc442acea032447fc27c65d77caa55e6913bb5..3bd837499ea359181022430d93bb5d62f29c133e 100644 --- a/src/Rust/Cargo.toml +++ b/src/Rust/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["vvs_cli", "vvs_lua", "vvs_ass", "vvs_repl"] +members = ["vvs_cli", "vvs_lua", "vvs_ass", "vvs_repl", "vvs_procmacro"] [workspace.package] version = "0.4.0" diff --git a/src/Rust/vvs_ass/Cargo.toml b/src/Rust/vvs_ass/Cargo.toml index f0f939ba0e726c4ffe942e1abbd25bd04d372e4f..d0b222ee62931a1d5bd0c6560d6fe38d9588ba73 100644 --- a/src/Rust/vvs_ass/Cargo.toml +++ b/src/Rust/vvs_ass/Cargo.toml @@ -7,6 +7,8 @@ license.workspace = true description.workspace = true [dependencies] +vvs_procmacro = { path = "../vvs_procmacro" } + lazy_static.workspace = true thiserror.workspace = true anyhow.workspace = true diff --git a/src/Rust/vvs_ass/src/elements/line.rs b/src/Rust/vvs_ass/src/elements/line.rs new file mode 100644 index 0000000000000000000000000000000000000000..3ed50825a9de0e190ccdecb86a25125ad950bf2d --- /dev/null +++ b/src/Rust/vvs_ass/src/elements/line.rs @@ -0,0 +1,10 @@ +use crate::{elements::syllabes::ASSSyllabesPtr, ASSAuxTablePtr, ASSPositionPtr}; + +#[derive(Debug, Clone, PartialEq)] +pub struct ASSLine { + pub position: ASSPositionPtr, + pub content: ASSSyllabesPtr, + pub aux: ASSAuxTablePtr, +} + +pub type ASSLinePtr = crate::Ptr<ASSLine>; diff --git a/src/Rust/vvs_ass/src/elements/lines.rs b/src/Rust/vvs_ass/src/elements/lines.rs new file mode 100644 index 0000000000000000000000000000000000000000..87eabd77f85dd8255d0aac9cb33e5ccc8e5e5c76 --- /dev/null +++ b/src/Rust/vvs_ass/src/elements/lines.rs @@ -0,0 +1,10 @@ +use crate::{elements::line::ASSLinePtr, ASSAuxTablePtr, ASSPositionPtr}; + +#[derive(Debug, Clone, PartialEq)] +pub struct ASSLines { + pub position: ASSPositionPtr, + pub content: Vec<ASSLinePtr>, + pub aux: ASSAuxTablePtr, +} + +pub type ASSLinesPtr = crate::Ptr<ASSLines>; diff --git a/src/Rust/vvs_ass/src/elements/mod.rs b/src/Rust/vvs_ass/src/elements/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..b0808c07612abd432d5806be6c128bcfa6d61b21 --- /dev/null +++ b/src/Rust/vvs_ass/src/elements/mod.rs @@ -0,0 +1,9 @@ +mod line; +mod lines; +mod syllabe; +mod syllabes; + +pub use line::*; +pub use lines::*; +pub use syllabe::*; +pub use syllabes::*; diff --git a/src/Rust/vvs_ass/src/elements/syllabe.rs b/src/Rust/vvs_ass/src/elements/syllabe.rs new file mode 100644 index 0000000000000000000000000000000000000000..1d412182b0be418bdb1ada8a2f4c365e777da42e --- /dev/null +++ b/src/Rust/vvs_ass/src/elements/syllabe.rs @@ -0,0 +1,10 @@ +use crate::{ASSAuxTablePtr, ASSPositionPtr}; + +#[derive(Debug, Clone, PartialEq)] +pub struct ASSSyllabe { + pub position: ASSPositionPtr, + pub content: String, + pub aux: ASSAuxTablePtr, +} + +pub type ASSSyllabePtr = crate::Ptr<ASSSyllabe>; diff --git a/src/Rust/vvs_ass/src/elements/syllabes.rs b/src/Rust/vvs_ass/src/elements/syllabes.rs new file mode 100644 index 0000000000000000000000000000000000000000..f57f8a759a3ba128751e20e2ab6387c5f2c7050e --- /dev/null +++ b/src/Rust/vvs_ass/src/elements/syllabes.rs @@ -0,0 +1,10 @@ +use crate::{elements::syllabe::ASSSyllabePtr, ASSAuxTablePtr, ASSPositionPtr}; + +#[derive(Debug, Clone, PartialEq)] +pub struct ASSSyllabes { + pub position: ASSPositionPtr, + pub content: Vec<ASSSyllabePtr>, + pub aux: ASSAuxTablePtr, +} + +pub type ASSSyllabesPtr = crate::Ptr<ASSSyllabes>; diff --git a/src/Rust/vvs_ass/src/lib.rs b/src/Rust/vvs_ass/src/lib.rs index c554fadb9a1724de666c5314c19154e1613e23ac..783ab954e5a80e6e38f2809d5bf962ac62b11591 100644 --- a/src/Rust/vvs_ass/src/lib.rs +++ b/src/Rust/vvs_ass/src/lib.rs @@ -1,5 +1,20 @@ //! ASS objects for Vivy. -pub mod position; -pub mod types; -pub mod values; +mod elements; +mod position; +mod types; +mod values; + +pub use elements::*; +pub use position::*; +pub use types::*; +pub use values::*; + +pub type Ptr<T> = std::rc::Rc<std::cell::RefCell<T>>; + +#[macro_export] +macro_rules! ptr { + ($expr: expr) => { + std::rc::Rc::new(std::cell::RefCell::new($expr)) + }; +} diff --git a/src/Rust/vvs_ass/src/position.rs b/src/Rust/vvs_ass/src/position.rs index 668e0f976d679fa425fe616bcbd930fcf37aa908..7012e97a368c3da5cdf418508d5d8d011700f2be 100644 --- a/src/Rust/vvs_ass/src/position.rs +++ b/src/Rust/vvs_ass/src/position.rs @@ -1,5 +1,40 @@ +/// The position of an object from the top left corner. The real position depends on the align of +/// the object. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct Position { - x: i64, - y: i64, +pub struct ASSPosition { + pub x: i64, + pub y: i64, } + +/// The alignement of the object. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ASSAlign { + /// Bottom left + BL = 1, + + /// Bottom center + BC = 2, + + /// Bottom right + BR = 3, + + /// Center left + CL = 4, + + /// Center center + CC = 5, + + /// Center right + CR = 6, + + /// Top left + TL = 7, + + /// Top center + TC = 8, + + /// Top right + TR = 9, +} + +pub type ASSPositionPtr = crate::Ptr<ASSPosition>; diff --git a/src/Rust/vvs_ass/src/types.rs b/src/Rust/vvs_ass/src/types.rs index a4ea3822185d4901d1f41969ef50cb3ca4cef2c8..6d6928b2cf936f6be710cad1526b7e5569208ee9 100644 --- a/src/Rust/vvs_ass/src/types.rs +++ b/src/Rust/vvs_ass/src/types.rs @@ -1,9 +1,10 @@ use std::str::FromStr; use thiserror::Error; +use vvs_procmacro::{EnumVariantCount, EnumVariantIter}; /// Represents the types of the ASS types that can be manipulated. By combining them we can create /// a tree of the ASS elements. We have: -/// ```no_run,skip +/// ```ignore /// - Lines /// - pos: AssPosition /// - aux: HashMap<String, AssAuxValue> @@ -30,22 +31,54 @@ use thiserror::Error; /// /// We also derive the Ord/PartialOrd crates. The types are ordered from the Lines to the Syllabe. /// Thus if a type is greater than another one, the former must contains the latter. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, EnumVariantCount, EnumVariantIter)] pub enum ASSType { - Lines, - Line, - Syllabes, - Syllabe, + Lines = 0, + Line = 1, + Syllabes = 2, + Syllabe = 3, +} + +impl ASSType { + pub fn as_str(&self) -> &'static str { + match self { + ASSType::Lines => "lines", + ASSType::Line => "line", + ASSType::Syllabes => "syllabes", + ASSType::Syllabe => "syllabe", + } + } + + pub fn as_padded_str(&self) -> &'static str { + match self { + ASSType::Lines => "lines ", + ASSType::Line => "line ", + ASSType::Syllabes => "syllabes", + ASSType::Syllabe => "syllabe ", + } + } +} + +impl AsRef<str> for ASSType { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl std::fmt::Display for ASSType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.as_str()) + } } #[derive(Debug, Error)] -pub enum AssTypeFromStrError { +pub enum ASSTypeFromStrError { #[error("unknown ass structure type '{0}', expected: lines/line/syllabe/syllabes")] Unknown(String), } impl FromStr for ASSType { - type Err = AssTypeFromStrError; + type Err = ASSTypeFromStrError; fn from_str(s: &str) -> Result<Self, Self::Err> { match s { @@ -53,7 +86,7 @@ impl FromStr for ASSType { "lines" => Ok(Self::Lines), "syllabe" => Ok(Self::Syllabe), "syllabes" => Ok(Self::Syllabes), - _ => Err(AssTypeFromStrError::Unknown(s.to_string())), + _ => Err(ASSTypeFromStrError::Unknown(s.to_string())), } } } diff --git a/src/Rust/vvs_ass/src/values.rs b/src/Rust/vvs_ass/src/values.rs index 7b64de9e989915ca547af2c4beab1b0fc94464a0..7c656b477963aac846ffb1b7e00fcbfa0e4b444b 100644 --- a/src/Rust/vvs_ass/src/values.rs +++ b/src/Rust/vvs_ass/src/values.rs @@ -1,7 +1,113 @@ +use std::{cell::RefCell, collections::HashMap, convert::TryFrom, rc::Rc}; + +/// The values that can be added to an ASS element. #[derive(Debug, Clone, PartialEq)] -pub enum AssAuxValue { +pub enum ASSAuxValue { Integer(i64), Floating(f64), Boolean(bool), String(String), } + +/// The auxiliary table of user values associated to ASS elements. +#[derive(Debug, Default, Clone, PartialEq)] +pub struct ASSAuxTable(HashMap<String, ASSAuxValue>); + +pub type ASSAuxTablePtr = Rc<RefCell<ASSAuxTable>>; + +impl ASSAuxValue { + pub fn type_str(&self) -> &'static str { + match self { + ASSAuxValue::Integer(_) => "integer", + ASSAuxValue::Floating(_) => "floating", + ASSAuxValue::Boolean(_) => "boolean", + ASSAuxValue::String(_) => "string", + } + } + + pub fn coerce_like(self, like: &ASSAuxValue) -> Option<ASSAuxValue> { + use ASSAuxValue::*; + match (&self, like) { + (Floating(_), Floating(_)) + | (Integer(_), Integer(_)) + | (Boolean(_), Boolean(_)) + | (String(_), String(_)) => Some(self), + + (Integer(v), Floating(_)) => Some(Floating(i32::try_from(*v).ok()? as f64)), + (Integer(0), Boolean(_)) => Some(Boolean(false)), + (Integer(_), Boolean(_)) => Some(Boolean(true)), + + (Boolean(v), String(_)) => Some(String(format!("{v}"))), + (Integer(v), String(_)) => Some(String(format!("{v}"))), + (Floating(v), String(_)) => Some(String(format!("{v}"))), + + (Boolean(v), Integer(_)) => Some(Integer(*v as i64)), + + (String(_), Integer(_)) => todo!(), + (String(_), Floating(_)) => todo!(), + (String(_), Boolean(_)) => todo!(), + + (Floating(_), Integer(_)) | (Floating(_), Boolean(_)) | (Boolean(_), Floating(_)) => { + log::error!(target: "lua", "invalid convertion from type `{}` to `{}`", self.type_str(), like.type_str()); + None + } + } + } +} + +impl std::fmt::Display for ASSAuxValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ASSAuxValue::Floating(val) => write!(f, "{val}"), + ASSAuxValue::Integer(val) => write!(f, "{val}"), + ASSAuxValue::Boolean(val) => write!(f, "{val}"), + ASSAuxValue::String(val) => f.write_str(&val), + } + } +} + +impl ASSAuxTable { + pub fn new() -> Self { + Default::default() + } + + pub fn into_ptr(self) -> ASSAuxTablePtr { + crate::ptr! { self } + } + + pub fn set(&mut self, name: impl AsRef<str>, value: ASSAuxValue) { + let name = name.as_ref(); + let new = value.type_str(); + match self.0.get_mut(name) { + Some(old) => match value.coerce_like(old) { + Some(new) => *old = new, + None => log::error!( + target: "lua", + "can't set new value for `{name}`, old value was of type `{}` and new one is of type `{new}`", + old.type_str() + ), + }, + None => { + let _ = self.0.insert(name.to_string(), value); + } + } + } + + pub fn get_copy(&self, name: impl AsRef<str>) -> Option<ASSAuxValue> { + self.0.get(name.as_ref()).cloned() + } + + pub fn get(&self, name: impl AsRef<str>) -> Option<&ASSAuxValue> { + self.0.get(name.as_ref()) + } + + pub fn get_mut(&mut self, name: impl AsRef<str>) -> Option<&mut ASSAuxValue> { + self.0.get_mut(name.as_ref()) + } +} + +impl FromIterator<(String, ASSAuxValue)> for ASSAuxTable { + fn from_iter<T: IntoIterator<Item = (String, ASSAuxValue)>>(iter: T) -> Self { + Self(HashMap::from_iter(iter)) + } +} diff --git a/src/Rust/vvs_lua/Cargo.toml b/src/Rust/vvs_lua/Cargo.toml index 05d8712fcd0edc1a5374b386f45db959bfaecdc9..7b7368080ded4fe8d48e003490ecd36ff1d105f7 100644 --- a/src/Rust/vvs_lua/Cargo.toml +++ b/src/Rust/vvs_lua/Cargo.toml @@ -10,6 +10,7 @@ description.workspace = true vvs_ass = { path = "../vvs_ass" } thiserror.workspace = true +paste.workspace = true toml.workspace = true log.workspace = true diff --git a/src/Rust/vvs_lua/src/data/actions.rs b/src/Rust/vvs_lua/src/data/actions.rs new file mode 100644 index 0000000000000000000000000000000000000000..67e46f1a997615345fd89a72bdaa1bbe8f824aa0 --- /dev/null +++ b/src/Rust/vvs_lua/src/data/actions.rs @@ -0,0 +1,77 @@ +use crate::{data::lua_wrapper::LuaAssAuxValue, traits::TypedValue, types::Type}; +use mlua::prelude::*; +use vvs_ass::ASSAuxValue; + +/// Structure used to register auxiliary data in an ASS element by typing either: +/// - `data "line:a"` +/// - `data { "line:a", type = "number", default = 0, doc = "..." }` +#[derive(Debug, Clone, PartialEq)] +pub(crate) struct RegisterDataValue { + pub ty: Type, + pub value: LuaAssAuxValue, + pub doc: Option<String>, +} + +impl<'lua> FromLua<'lua> for RegisterDataValue { + fn from_lua(lua_value: LuaValue<'lua>, lua: &'lua Lua) -> LuaResult<Self> { + match lua_value { + LuaValue::Table(table) => { + let value: LuaAssAuxValue = match table.get::<_, LuaValue>("value").ok() { + None | Some(LuaValue::Nil) => { + return Err(LuaError::RuntimeError(format!( + "you must specify a default value in a data declaration" + ))) + } + Some(value) => match value { + LuaValue::Boolean(v) => LuaAssAuxValue::from(ASSAuxValue::Boolean(v)), + LuaValue::Integer(v) => LuaAssAuxValue::from(ASSAuxValue::Integer(v)), + LuaValue::Number(v) => LuaAssAuxValue::from(ASSAuxValue::Floating(v)), + LuaValue::String(v) => LuaAssAuxValue::from(ASSAuxValue::String( + v.to_string_lossy().to_string(), + )), + value => { + return Err(LuaError::FromLuaConversionError { + from: value.type_name(), + to: "LuaAssAuxValue", + message: None, + }) + } + }, + }; + let ty = match table.get::<_, LuaValue>("type").ok() { + None | Some(LuaValue::Nil) => { + return Err(LuaError::RuntimeError(format!( + "you must specify a type in a data declaration" + ))) + } + Some(ty) => Type::from_lua(ty, lua)?, + }; + let doc = match table.get::<_, LuaValue>("doc").ok() { + None | Some(LuaValue::Nil) => None, + Some(LuaValue::String(doc)) => Some(doc.to_string_lossy().to_string()), + Some(value) => { + return Err(LuaError::RuntimeError(format!( + "value of type '{}' can't be a docstring, expected a 'string'", + value.type_name() + ))) + } + }; + if value.ty().ne(&ty) { + return Err(LuaError::RuntimeError(format!( + "tried to register a value of type '{}' when declaring the option of type '{ty}'", + value.ty() + ))); + } + Ok(Self { doc, ty, value }) + } + + _ => Err(LuaError::FromLuaConversionError { + from: lua_value.type_name(), + to: "RegisterDataValue", + message: Some( + "expected a string or a table with the 'data' instruction".to_string(), + ), + }), + } + } +} diff --git a/src/Rust/vvs_lua/src/data/lua_wrapper.rs b/src/Rust/vvs_lua/src/data/lua_wrapper.rs new file mode 100644 index 0000000000000000000000000000000000000000..e0cb563e5ddf2b1c42351f12634d7f94ed7ec303 --- /dev/null +++ b/src/Rust/vvs_lua/src/data/lua_wrapper.rs @@ -0,0 +1,120 @@ +//! Wraps the ASS element types and implement some helper traits. + +use crate::traits::TypedValue; +use mlua::prelude::*; +use vvs_ass::{ + ASSAuxTablePtr, ASSAuxValue, ASSLinePtr, ASSLinesPtr, ASSPositionPtr, ASSSyllabePtr, + ASSSyllabesPtr, +}; + +macro_rules! wrap_ass2lua { + ($($type: ident + $(, $fields: ident -> $add_fields: expr + , $methods: ident -> $add_methods: expr)? + );+ $(;)?) => { + $(wrap_ass2lua!(@@private $type $(; $fields -> $add_fields ; $methods -> $add_methods)?);)+ + }; + + (@@decl $type: ident) => { + paste::paste! { + #[derive(Debug, Clone, PartialEq)] + #[repr(transparent)] + pub(crate) struct [< LuaAss $type >] ([< ASS $type >]); + + impl [< LuaAss $type >] { + #[allow(dead_code)] + pub fn into_inner(self) -> [< ASS $type >] { + self.0 + } + + #[allow(dead_code)] + pub fn as_inner(&self) -> &[< ASS $type >] { + &self.0 + } + } + + impl From< [< ASS $type >] > for [< LuaAss $type >] { + fn from(value: [< ASS $type >]) -> Self { + Self(value) + } + } + } + }; + + (@@private $type: ident) => { + wrap_ass2lua!(@@decl $type); + paste::paste! { impl LuaUserData for [< LuaAss $type >] { } } + }; + + (@@private $type: ident + ; $fields : ident -> $add_fields : expr + ; $methods: ident -> $add_methods: expr) => { + wrap_ass2lua!(@@decl $type); + paste::paste! { + impl LuaUserData for [< LuaAss $type >] { + fn add_fields <'lua, F: LuaUserDataFields <'lua, Self>>($fields: &mut F) { $add_fields } + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>($methods: &mut M) { $add_methods } + } + } + }; +} + +macro_rules! add_method { + ($fields: expr => @aux) => { + add_method! { $fields => aux @ LuaAssAuxTablePtr } + }; + + ($fields: expr => $field: ident @ $wrapper: ident) => { + add_method! { get $fields => $field @ $wrapper } + add_method! { set $fields => $field @ $wrapper } + }; + + (get $fields: expr => $field: ident @ $wrapper: ident) => { + $fields.add_field_method_get(stringify!($field), |_, Self(this)| { + Ok($wrapper(this.borrow().$field.clone())) + }); + }; + + (set $fields: expr => $field: ident @ $wrapper: ident) => { + $fields.add_field_method_set(stringify!($field), |_, Self(this), $wrapper(val)| { + this.borrow_mut().$field = val; + Ok(()) + }); + }; +} + +wrap_ass2lua! { + AuxValue; + AuxTablePtr; + PositionPtr; + LinePtr, + f -> { + add_method! { f => @aux } + add_method! { f => position @ LuaAssPositionPtr } + }, + _m -> {}; + LinesPtr, + f -> { + add_method! { f => @aux } + add_method! { f => position @ LuaAssPositionPtr } + }, + _m -> {}; + SyllabePtr, + f -> { + add_method! { f => @aux } + add_method! { f => position @ LuaAssPositionPtr } + }, + _m -> {}; + SyllabesPtr, + f -> { + add_method! { f => @aux } + add_method! { f => position @ LuaAssPositionPtr } + }, + _m -> {}; +} + +impl TypedValue for LuaAssAuxValue { + fn ty(&self) -> crate::types::Type { + self.0.ty() + } +} diff --git a/src/Rust/vvs_lua/src/datas/mod.rs b/src/Rust/vvs_lua/src/data/mod.rs similarity index 100% rename from src/Rust/vvs_lua/src/datas/mod.rs rename to src/Rust/vvs_lua/src/data/mod.rs diff --git a/src/Rust/vvs_lua/src/data/register.rs b/src/Rust/vvs_lua/src/data/register.rs new file mode 100644 index 0000000000000000000000000000000000000000..c2095987b01b156980f4e45488db39dbf2f5ce8f --- /dev/null +++ b/src/Rust/vvs_lua/src/data/register.rs @@ -0,0 +1,223 @@ +use crate::data::{actions::RegisterDataValue, lua_wrapper::LuaAssAuxTablePtr}; +use mlua::prelude::*; +use std::{ + cell::RefCell, + collections::{HashMap, HashSet}, + rc::Rc, +}; +use thiserror::Error; +use vvs_ass::{ASSAuxTable, ASSType, ASSTYPE_LENGTH, ASSTYPE_VALUES}; + +#[derive(Debug, Clone, PartialEq)] +struct VivyDataValueHashMap { + ass_type: ASSType, + table: HashMap<String, RegisterDataValue>, + cached_table: LuaAssAuxTablePtr, +} + +#[derive(Debug, Error)] +pub(crate) enum VivyDataRegisterError { + #[error("{0}")] + Lua(LuaError), + + #[error("vivy data already marked as to register")] + AlreadyMarkedAsRegister, + + #[error("vivy data already registered")] + AlreadyRegistered, +} + +/// The structure used to register auxiliary fields in ASS structures. +#[derive(Debug, Clone, PartialEq)] +pub(crate) struct VivyDataRegister { + registered: [VivyDataValueHashMap; ASSTYPE_LENGTH], + will_register: HashSet<String>, +} + +pub(crate) type VivyDataRegisterPtr = Rc<RefCell<VivyDataRegister>>; + +fn decode_name(name: &str) -> LuaResult<(&str, ASSType)> { + let Some((ass_type, name)) = name.split_once(':') else { + return Err(LuaError::RuntimeError(format!( + "invalid data name, got '{name}', expected: 'ass_type:data_name'" + ))); + }; + let ass_type = ass_type.parse::<ASSType>().map_err(|err| { + LuaError::RuntimeError(format!( + "failed to convert type '{ass_type}' to an vvs_ass::ASSType\n{err}" + )) + })?; + Ok((name, ass_type)) +} + +impl VivyDataValueHashMap { + fn new(ty: ASSType) -> Self { + Self { + ass_type: ty, + table: Default::default(), + cached_table: LuaAssAuxTablePtr::from(ASSAuxTable::default().into_ptr()), + } + } +} + +impl Default for VivyDataRegister { + fn default() -> Self { + Self { + will_register: Default::default(), + registered: [ + VivyDataValueHashMap::new(ASSType::Lines), + VivyDataValueHashMap::new(ASSType::Line), + VivyDataValueHashMap::new(ASSType::Syllabes), + VivyDataValueHashMap::new(ASSType::Syllabe), + ], + } + } +} + +impl VivyDataRegister { + pub fn new() -> Rc<RefCell<VivyDataRegister>> { + Default::default() + } + + pub fn compute_cached_tables(&mut self) { + for ty in ASSTYPE_VALUES { + let register = self.get_register_mut(*ty); + let table = LuaAssAuxTablePtr::from( + ASSAuxTable::from_iter( + register + .table + .iter() + .map(|(name, data)| (name.clone(), data.value.clone().into_inner())), + ) + .into_ptr(), + ); + register.cached_table = table; + } + } + + pub fn get_orphan_data_declarations(&self) -> impl Iterator<Item = (ASSType, &str)> { + self.will_register.iter().filter_map(|data| { + let (data, ass_type) = decode_name(data).expect("vivy internal error"); + (!self + .registered + .get(ass_type as usize) + .expect("vivy internal error") + .table + .contains_key(data)) + .then_some((ass_type, data)) + }) + } + + /// Get the default aux table for an ass element type. Returns the cached table. After + /// registering all the wanted values, you may use the + /// [VivyDataRegister::compute_cached_tables] before calling this function. + pub fn get_table(&self, ass_type: ASSType) -> LuaAssAuxTablePtr { + self.get_register(ass_type).cached_table.clone() + } + + /// Iter over the registered data names and types. + pub fn iter_registered(&self) -> impl Iterator<Item = (ASSType, &String)> { + self.registered.iter().flat_map( + |VivyDataValueHashMap { + ass_type, table, .. + }| { std::iter::repeat(*ass_type).zip(table.keys()) }, + ) + } + + /// Get the register data for a specific [ASSType]. If the ass type is not correct the function + /// will panic, but if you pass as correctly formed type it should be fine. + fn get_register_mut(&mut self, ass_type: ASSType) -> &mut VivyDataValueHashMap { + self.registered + .get_mut(ass_type as usize) + .expect("invalid ass element type passed") + } + + /// Get the register data for a specific [ASSType]. If the ass type is not correct the function + /// will panic, but if you pass as correctly formed type it should be fine. + fn get_register(&self, ass_type: ASSType) -> &VivyDataValueHashMap { + self.registered + .get(ass_type as usize) + .expect("invalid ass element type passed") + } + + /// Call to say that we will register a named option. If the option was already registered or + /// flagged as 'to register', raise an error. If the name is not valid, raise an error. + fn will_register_data(&mut self, name: String) -> Result<(), VivyDataRegisterError> { + let (data_name, ass_type) = decode_name(&name).map_err(VivyDataRegisterError::Lua)?; + if self.get_register(ass_type).table.get(data_name).is_some() { + Err(VivyDataRegisterError::AlreadyRegistered) + } else if !self.will_register.insert(name) { + Err(VivyDataRegisterError::AlreadyMarkedAsRegister) + } else { + Ok(()) + } + } + + /// Register the data, returns an error if the data was already registered. If the data was not + /// flagged as 'to register', also raise an error. + fn register_data( + &mut self, + name: impl AsRef<str>, + value: RegisterDataValue, + ) -> Result<(), VivyDataRegisterError> { + let (name, ass_type) = decode_name(name.as_ref()).map_err(VivyDataRegisterError::Lua)?; + let table = &mut self.get_register_mut(ass_type).table; + match table.get(name) { + Some(_) => Err(VivyDataRegisterError::AlreadyRegistered), + None => { + table.insert(name.to_string(), value); + Ok(()) + } + } + } +} + +impl LuaUserData for VivyDataRegister { + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_method_mut("will_register", |_, this, name: String| { + this.will_register_data(name.clone()) + .map_err(|err| match err { + VivyDataRegisterError::Lua(lua) => lua, + err => LuaError::RuntimeError(format!( + "failed to mark as 'to register' data '{name}': {err}" + )), + }) + }); + + methods.add_method_mut( + "register", + |_, this, (name, value): (String, RegisterDataValue)| { + this.register_data(&name, value).map_err(|err| match err { + VivyDataRegisterError::Lua(lua) => lua, + err => { + LuaError::RuntimeError(format!("failed to register data '{name}': {err}")) + } + }) + }, + ) + } +} + +#[test] +fn test_data_register_creation() { + let reg = VivyDataRegister::new(); + let reg: &VivyDataRegister = &*reg.borrow(); + assert_eq!(*reg, Default::default()); + + macro_rules! test_item { + ($item: ident) => { + assert_eq!( + reg.registered + .get(ASSType::$item as usize) + .unwrap() + .ass_type, + ASSType::$item + ); + }; + } + + test_item! { Lines } + test_item! { Line } + test_item! { Syllabes } + test_item! { Syllabe } +} diff --git a/src/Rust/vvs_lua/src/datas/actions.rs b/src/Rust/vvs_lua/src/datas/actions.rs deleted file mode 100644 index 7730007d40bdd05c7273a488cbda1ebbe49424ec..0000000000000000000000000000000000000000 --- a/src/Rust/vvs_lua/src/datas/actions.rs +++ /dev/null @@ -1,98 +0,0 @@ -use crate::{datas::lua_wrapper::LuaAssAuxValue, traits::TypedValue, types::Type}; -use mlua::prelude::*; - -/// Structure used to register auxiliary data in an ASS element by typing either: -/// - `data "line:a"` -/// - `data { "line:a", type = "number", default = 0, doc = "..." }` -#[derive(Debug, Clone, PartialEq)] -pub(crate) struct RegisterDataValue { - pub name: String, - pub ass_type: vvs_ass::types::ASSType, - pub doc: Option<String>, - pub ty: Option<Type>, - pub value: Option<LuaAssAuxValue>, -} - -impl RegisterDataValue { - fn decode_name(name: &str) -> LuaResult<(&str, vvs_ass::types::ASSType)> { - let Some((ass_type, name)) = name.split_once(':') else { - return Err(LuaError::RuntimeError(format!( - "invalid data name, got '{name}', expected: 'ass_type:data_name'" - ))); - }; - let ass_type = ass_type.parse::<vvs_ass::types::ASSType>().map_err(|err| { - LuaError::RuntimeError(format!( - "failed to convert type '{ass_type}' to an vvs_ass::ASSType\n{err}" - )) - })?; - Ok((name, ass_type)) - } -} - -impl<'lua> FromLua<'lua> for RegisterDataValue { - fn from_lua(lua_value: LuaValue<'lua>, lua: &'lua Lua) -> LuaResult<Self> { - match lua_value { - LuaValue::String(name) => { - let name = name.to_string_lossy(); - let (name, ass_type) = Self::decode_name(&name)?; - Ok(Self { - name: name.to_string(), - ass_type, - doc: None, - ty: None, - value: None, - }) - } - - LuaValue::Table(table) => { - let name: String = table.get(1).map_err(|_| { - LuaError::RuntimeError( - "failed to get the name in the 'data' instruction".to_string(), - ) - })?; - let (name, ass_type) = Self::decode_name(&name)?; - let value = match table.get::<_, LuaValue>("value").ok() { - None | Some(LuaValue::Nil) => None, - Some(value) => Some(LuaAssAuxValue::from_lua(value, lua)?), - }; - let ty = match table.get::<_, LuaValue>("type").ok() { - None | Some(LuaValue::Nil) => None, - Some(ty) => Some(Type::from_lua(ty, lua)?), - }; - let doc = match table.get::<_, LuaValue>("doc").ok() { - None | Some(LuaValue::Nil) => None, - Some(LuaValue::String(doc)) => Some(doc.to_string_lossy().to_string()), - Some(value) => { - return Err(LuaError::RuntimeError(format!( - "value of type '{}' can't be a docstring, expected a 'string'", - value.type_name() - ))) - } - }; - if let (Some(value), Some(ty)) = (value.as_ref(), ty.as_ref()) { - if value.ty().ne(ty) { - return Err(LuaError::RuntimeError(format!( - "tried to register a value of type '{}' when declaring the option of type '{ty}'", - value.ty() - ))); - } - } - Ok(Self { - name: name.to_string(), - ass_type, - doc, - ty, - value, - }) - } - - _ => Err(LuaError::FromLuaConversionError { - from: lua_value.type_name(), - to: "RegisterDataValue", - message: Some( - "expected a string or a table with the 'data' instruction".to_string(), - ), - }), - } - } -} diff --git a/src/Rust/vvs_lua/src/datas/lua_wrapper.rs b/src/Rust/vvs_lua/src/datas/lua_wrapper.rs deleted file mode 100644 index b4ba36976c5fc6a5f09c179786d610cccc60e0a7..0000000000000000000000000000000000000000 --- a/src/Rust/vvs_lua/src/datas/lua_wrapper.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! Wraps the ASS element types and implement some helper traits. - -use crate::traits::TypedValue; -use mlua::prelude::*; -use vvs_ass::values::AssAuxValue; - -#[derive(Debug, Clone, PartialEq)] -pub(crate) struct LuaAssAuxValue(AssAuxValue); - -impl LuaUserData for LuaAssAuxValue { - fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(_fields: &mut F) {} - - fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(_methods: &mut M) {} -} - -impl TypedValue for LuaAssAuxValue { - fn ty(&self) -> crate::types::Type { - self.0.ty() - } -} diff --git a/src/Rust/vvs_lua/src/datas/register.rs b/src/Rust/vvs_lua/src/datas/register.rs deleted file mode 100644 index d082ac77d2e319fc6fb52fff02f53946e16f4e36..0000000000000000000000000000000000000000 --- a/src/Rust/vvs_lua/src/datas/register.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::datas::actions::RegisterDataValue; -use mlua::prelude::*; -use std::{cell::RefCell, collections::HashMap, rc::Rc}; - -/// The structure used to register auxiliary fields in ASS structures. -#[derive(Debug, Clone, PartialEq, Default)] -pub(crate) struct VivyDataRegister { - registered: HashMap<String, RegisterDataValue>, -} - -pub(crate) type VivyDataRegisterPtr = Rc<RefCell<VivyDataRegister>>; - -impl VivyDataRegister { - pub fn new() -> Rc<RefCell<VivyDataRegister>> { - Default::default() - } - - fn register_data(&mut self, value: RegisterDataValue) -> Result<(), String> { - todo!() - } -} - -impl LuaUserData for VivyDataRegister { - fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_method_mut("register", |_, this, value: RegisterDataValue| { - this.register_data(value).map_err(LuaError::RuntimeError) - }) - } -} diff --git a/src/Rust/vvs_lua/src/functions.rs b/src/Rust/vvs_lua/src/functions.rs index 24586a6df9e14ad5137976b6ccb2676ca20aaa43..6834fc369da8c88d52b7af7dc822f6dd53bb021b 100644 --- a/src/Rust/vvs_lua/src/functions.rs +++ b/src/Rust/vvs_lua/src/functions.rs @@ -1,11 +1,11 @@ -use crate::{datas::VivyDataRegister, libs, options::VivyOptionRegister, TomlOptions}; +use crate::{data::VivyDataRegister, libs, options::VivyOptionRegister, TomlOptions}; use mlua::{chunk, prelude::*}; use std::path::Path; pub fn setup(options: Option<TomlOptions>) -> LuaResult<Lua> { let options = VivyOptionRegister::new(options.unwrap_or_default()); let version = env!("CARGO_PKG_VERSION"); - let datas = VivyDataRegister::new(); + let data = VivyDataRegister::new(); let lua = Lua::new_with( LuaStdLib::MATH | LuaStdLib::TABLE | LuaStdLib::STRING | LuaStdLib::PACKAGE, LuaOptions::new().catch_rust_panics(true), @@ -29,7 +29,7 @@ pub fn setup(options: Option<TomlOptions>) -> LuaResult<Lua> { module = nil _VERSION = nil local options = $options - local datas = $datas + local data = $data local ReadOnly = { package = nil, coroutine = nil, @@ -42,7 +42,7 @@ pub fn setup(options: Option<TomlOptions>) -> LuaResult<Lua> { // Import Vivy $requires "vivy" vivy:___set_options(options) - vivy:___set_datas(datas) + vivy:___set_data(data) ReadOnly.vivy = vivy vivy = nil @@ -70,8 +70,11 @@ pub fn setup(options: Option<TomlOptions>) -> LuaResult<Lua> { error("not implemented", 2) end - function ReadOnly.data (table) - error("not implemented", 2) + function ReadOnly.data (name) + data:will_register(name) + return function (table) + data:register(name, table) + end end function ReadOnly.set (name) diff --git a/src/Rust/vvs_lua/src/lib.rs b/src/Rust/vvs_lua/src/lib.rs index 79489340bb289e501a6968432ecf9fba964b97db..20eec63bba725fd4d1315263d577d944df014178 100644 --- a/src/Rust/vvs_lua/src/lib.rs +++ b/src/Rust/vvs_lua/src/lib.rs @@ -3,7 +3,7 @@ /// Re-export mlua pub use mlua; -mod datas; +mod data; mod error; mod functions; mod libs; diff --git a/src/Rust/vvs_lua/src/libs/vivy.rs b/src/Rust/vvs_lua/src/libs/vivy.rs index a0dccd54826135de610ca7abec4b11c0cfc5eccd..8f8bdf26f14e1ccc2d79eab9dd60d722a01dd9e8 100644 --- a/src/Rust/vvs_lua/src/libs/vivy.rs +++ b/src/Rust/vvs_lua/src/libs/vivy.rs @@ -1,13 +1,13 @@ //! Provides the vivy runtime. -use crate::{datas::VivyDataRegisterPtr, options::VivyOptionRegisterPtr, traits::TypedValue}; +use crate::{data::VivyDataRegisterPtr, options::VivyOptionRegisterPtr, traits::TypedValue}; use mlua::prelude::*; use std::path::PathBuf; #[derive(Default, Debug)] pub struct Vivy { options: Option<VivyOptionRegisterPtr>, - datas: Option<VivyDataRegisterPtr>, + data: Option<VivyDataRegisterPtr>, path: Vec<String>, loaded: Vec<String>, } @@ -63,8 +63,8 @@ impl LuaUserData for Vivy { |_, this, options: VivyOptionRegisterPtr| Ok(this.options = Some(options)), ); - methods.add_method_mut("___set_datas", |_, this, datas: VivyDataRegisterPtr| { - Ok(this.datas = Some(datas)) + methods.add_method_mut("___set_data", |_, this, data: VivyDataRegisterPtr| { + Ok(this.data = Some(data)) }); methods.add_method_mut("___finish_setup", |lua, this, ()| { @@ -78,6 +78,11 @@ impl LuaUserData for Vivy { lua.globals().raw_set(option.as_str(), value)?; } } + + if let Some(ref data) = this.data { + data.borrow_mut().compute_cached_tables() + } + Ok(()) }); @@ -130,6 +135,32 @@ impl LuaUserData for Vivy { } } + if let Some(data) = this.data.as_ref() { + let data = data.borrow(); + let added: Vec<_> = data + .iter_registered() + .map(|(ty, name)| (ty, name, format!("{ty}.aux.{name}"))) + .collect(); + if !added.is_empty() { + println!(" # Data"); + let padding = added.iter().map(|(_, _, name)| name.len()).max(); + let padding = padding.unwrap_or_default(); + for (ty, data_name, format_name) in added { + println!( + " - data {format_name:padding$} = {}", + data.get_table(ty) + .as_inner() + .borrow() + .get(data_name) + .expect("vivy internal error"), + ); + } + } + + let orphans: Vec<_> = data.get_orphan_data_declarations().collect(); + assert!(orphans.is_empty()); + } + Ok(()) }) } diff --git a/src/Rust/vvs_lua/src/traits.rs b/src/Rust/vvs_lua/src/traits.rs index 33af6770b61c6551aa46513189223ad8ac8bbc17..91e1f21a338390da8c00901965a70502c0014a2a 100644 --- a/src/Rust/vvs_lua/src/traits.rs +++ b/src/Rust/vvs_lua/src/traits.rs @@ -20,14 +20,14 @@ impl TypedValue for toml::Value { } } -impl TypedValue for vvs_ass::values::AssAuxValue { +impl TypedValue for vvs_ass::ASSAuxValue { fn ty(&self) -> Type { - use vvs_ass::values::AssAuxValue; + use vvs_ass::ASSAuxValue; match self { - AssAuxValue::Integer(_) => Type::Base(BaseType::Number), - AssAuxValue::Floating(_) => Type::Base(BaseType::Number), - AssAuxValue::Boolean(_) => Type::Base(BaseType::Boolean), - AssAuxValue::String(_) => Type::Base(BaseType::String), + ASSAuxValue::Integer(_) => Type::Base(BaseType::Number), + ASSAuxValue::Floating(_) => Type::Base(BaseType::Number), + ASSAuxValue::Boolean(_) => Type::Base(BaseType::Boolean), + ASSAuxValue::String(_) => Type::Base(BaseType::String), } } } diff --git a/src/Rust/vvs_procmacro/Cargo.toml b/src/Rust/vvs_procmacro/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..c7239a82228f3616d2bcba45a2802edc67b44601 --- /dev/null +++ b/src/Rust/vvs_procmacro/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "vvs_procmacro" +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true +description.workspace = true + +[lib] +proc-macro = true + +[dependencies] +syn = { version = "2.0", features = ["full"] } +quote = "1.0" +proc-macro2 = "1.0" diff --git a/src/Rust/vvs_procmacro/src/lib.rs b/src/Rust/vvs_procmacro/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..50a2d6fba57c54f530808e2b7e011690da5f933c --- /dev/null +++ b/src/Rust/vvs_procmacro/src/lib.rs @@ -0,0 +1,45 @@ +use proc_macro::TokenStream; +use proc_macro2::*; +use quote::*; + +#[proc_macro_derive(EnumVariantCount)] +pub fn derive_enum_variant_count(input: TokenStream) -> TokenStream { + let syn_item = syn::parse::<syn::DeriveInput>(input).expect("failed to parse input with syn"); + let (len, name) = match syn_item.data { + syn::Data::Enum(enum_item) => ( + enum_item.variants.len(), + Ident::new( + &format!("{}_LENGTH", syn_item.ident.to_string().to_uppercase()), + syn_item.ident.span(), + ), + ), + _ => panic!("EnumVariantCount only works on Enums"), + }; + quote! { pub const #name : usize = #len; }.into() +} + +#[proc_macro_derive(EnumVariantIter)] +pub fn derive_enum_variant_iter(input: TokenStream) -> TokenStream { + let syn_item = syn::parse::<syn::DeriveInput>(input).expect("failed to parse input with syn"); + let (enum_name, name, content) = match syn_item.data { + syn::Data::Enum(enum_item) => ( + syn_item.ident.clone(), + Ident::new( + &format!("{}_VALUES", syn_item.ident.to_string().to_uppercase()), + syn_item.ident.span(), + ), + syn::parse_str::<syn::Expr>(&format!( + "&[ {} ]", + enum_item + .variants + .into_iter() + .map(|variant| format!("{}::{}", syn_item.ident, variant.ident.to_string())) + .collect::<Vec<_>>() + .join(", "), + )) + .expect("failed generation of enum's variant list"), + ), + _ => panic!("EnumVariantIter only works on Enums"), + }; + quote! { pub const #name : &[#enum_name] = #content; }.into() +} diff --git a/utils/vvs/test_data.vvs b/utils/vvs/test_data.vvs new file mode 100644 index 0000000000000000000000000000000000000000..01553af81813ddbb4092976593c7f3fe24ebe670 --- /dev/null +++ b/utils/vvs/test_data.vvs @@ -0,0 +1,3 @@ +-- vim: ft=lua + +data "line:number" { type = "number", value = 0 }