From 1928e2ccb380b2b066ba583eacb381c36f3f52cc Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Tue, 20 Feb 2024 23:16:47 +1000 Subject: [PATCH] Refactor: Mv leon and leon-macros into another repo (#1628) * Refactor: Mv leon and leon-macros into another repo It's moved to https://github.com/cargo-bins/leon Signed-off-by: Jiahao XU * Fix CI: Rm `cargo-hack` check for `leon` Signed-off-by: Jiahao XU --------- Signed-off-by: Jiahao XU --- .github/workflows/release-pr.yml | 2 - Cargo.lock | 9 +- Cargo.toml | 2 - crates/binstalk-bins/Cargo.toml | 2 +- crates/binstalk-fetchers/Cargo.toml | 4 +- crates/binstalk-registry/Cargo.toml | 2 +- crates/binstalk/Cargo.toml | 2 +- crates/leon-macros/Cargo.toml | 19 -- crates/leon-macros/LICENSE-APACHE | 176 ---------- crates/leon-macros/LICENSE-MIT | 23 -- crates/leon-macros/src/lib.rs | 36 -- crates/leon-macros/tests/parsing.rs | 21 -- crates/leon/Cargo.toml | 21 -- crates/leon/LICENSE-APACHE | 176 ---------- crates/leon/LICENSE-MIT | 23 -- crates/leon/benches/.gitignore | 1 - crates/leon/benches/Cargo.lock | 431 ------------------------ crates/leon/benches/Cargo.toml | 30 -- crates/leon/benches/benches/others.rs | 89 ----- crates/leon/benches/benches/values.rs | 301 ----------------- crates/leon/benches/src/lib.rs | 0 crates/leon/fuzz/.gitignore | 4 - crates/leon/fuzz/Cargo.lock | 150 --------- crates/leon/fuzz/Cargo.toml | 27 -- crates/leon/fuzz/fuzz_targets/parser.rs | 9 - crates/leon/src/error.rs | 89 ----- crates/leon/src/lib.rs | 157 --------- crates/leon/src/macros.rs | 156 --------- crates/leon/src/main.rs | 61 ---- crates/leon/src/parser.rs | 334 ------------------ crates/leon/src/template.rs | 278 --------------- crates/leon/src/values.rs | 161 --------- justfile | 1 - 33 files changed, 11 insertions(+), 2786 deletions(-) delete mode 100644 crates/leon-macros/Cargo.toml delete mode 100644 crates/leon-macros/LICENSE-APACHE delete mode 100644 crates/leon-macros/LICENSE-MIT delete mode 100644 crates/leon-macros/src/lib.rs delete mode 100644 crates/leon-macros/tests/parsing.rs delete mode 100644 crates/leon/Cargo.toml delete mode 100644 crates/leon/LICENSE-APACHE delete mode 100644 crates/leon/LICENSE-MIT delete mode 100644 crates/leon/benches/.gitignore delete mode 100644 crates/leon/benches/Cargo.lock delete mode 100644 crates/leon/benches/Cargo.toml delete mode 100644 crates/leon/benches/benches/others.rs delete mode 100644 crates/leon/benches/benches/values.rs delete mode 100644 crates/leon/benches/src/lib.rs delete mode 100644 crates/leon/fuzz/.gitignore delete mode 100644 crates/leon/fuzz/Cargo.lock delete mode 100644 crates/leon/fuzz/Cargo.toml delete mode 100644 crates/leon/fuzz/fuzz_targets/parser.rs delete mode 100644 crates/leon/src/error.rs delete mode 100644 crates/leon/src/lib.rs delete mode 100644 crates/leon/src/macros.rs delete mode 100644 crates/leon/src/main.rs delete mode 100644 crates/leon/src/parser.rs delete mode 100644 crates/leon/src/template.rs delete mode 100644 crates/leon/src/values.rs diff --git a/.github/workflows/release-pr.yml b/.github/workflows/release-pr.yml index 0a858785..7e2f6614 100644 --- a/.github/workflows/release-pr.yml +++ b/.github/workflows/release-pr.yml @@ -21,8 +21,6 @@ on: - detect-wasi - fs-lock - normalize-path - - leon - - leon-macros version: description: Version to release required: true diff --git a/Cargo.lock b/Cargo.lock index 30a5080b..389edcba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2409,16 +2409,19 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "leon" -version = "3.0.0" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82a8693bd856b8b0596b6abed75d494ba6ca04b8e1b12be3a2ab947c305d8b1" dependencies = [ - "clap", "miette", "thiserror", ] [[package]] name = "leon-macros" -version = "1.0.1" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf3621546e1f1fedade073ad01f1c1bf561584a9b4c83c37728a28da69544aa" dependencies = [ "leon", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 6df9c1c0..8fda04af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,6 @@ members = [ "crates/fs-lock", "crates/normalize-path", "crates/detect-targets", - "crates/leon", - "crates/leon-macros", ] [profile.release] diff --git a/crates/binstalk-bins/Cargo.toml b/crates/binstalk-bins/Cargo.toml index 021f081c..42ef86cd 100644 --- a/crates/binstalk-bins/Cargo.toml +++ b/crates/binstalk-bins/Cargo.toml @@ -14,7 +14,7 @@ license = "GPL-3.0-only" atomic-file-install = { version = "1.0.1", path = "../atomic-file-install" } binstalk-types = { version = "0.7.0", path = "../binstalk-types" } compact_str = { version = "0.7.0", features = ["serde"] } -leon = { version = "3.0.0", path = "../leon" } +leon = "3.0.0" miette = "7.0.0" normalize-path = { version = "0.2.1", path = "../normalize-path" } thiserror = "1.0.52" diff --git a/crates/binstalk-fetchers/Cargo.toml b/crates/binstalk-fetchers/Cargo.toml index 972f9d77..55b58d19 100644 --- a/crates/binstalk-fetchers/Cargo.toml +++ b/crates/binstalk-fetchers/Cargo.toml @@ -18,8 +18,8 @@ bytes = "1.4.0" compact_str = { version = "0.7.0" } either = "1.8.1" itertools = "0.12.0" -leon = { version = "3.0.0", path = "../leon" } -leon-macros = { version = "1.0.1", path = "../leon-macros" } +leon = "3.0.0" +leon-macros = "1.0.1" miette = "7.0.0" minisign-verify = "0.2.1" once_cell = "1.18.0" diff --git a/crates/binstalk-registry/Cargo.toml b/crates/binstalk-registry/Cargo.toml index 5317bec7..41f96d03 100644 --- a/crates/binstalk-registry/Cargo.toml +++ b/crates/binstalk-registry/Cargo.toml @@ -17,7 +17,7 @@ binstalk-downloader = { version = "0.10.0", path = "../binstalk-downloader", def binstalk-types = { version = "0.7.0", path = "../binstalk-types" } cargo-toml-workspace = { version = "5.0.0", path = "../cargo-toml-workspace" } compact_str = { version = "0.7.0", features = ["serde"] } -leon = { version = "3.0.0", path = "../leon" } +leon = "3.0.0" miette = "7.0.0" normalize-path = { version = "0.2.1", path = "../normalize-path" } once_cell = "1.18.0" diff --git a/crates/binstalk/Cargo.toml b/crates/binstalk/Cargo.toml index 477d42eb..5a7072e9 100644 --- a/crates/binstalk/Cargo.toml +++ b/crates/binstalk/Cargo.toml @@ -22,7 +22,7 @@ detect-targets = { version = "0.1.15", path = "../detect-targets", features = [" either = "1.8.1" itertools = "0.12.0" jobslot = { version = "0.2.11", features = ["tokio"] } -leon = { version = "3.0.0", path = "../leon" } +leon = "3.0.0" maybe-owned = "0.3.4" miette = "7.0.0" semver = { version = "1.0.17", features = ["serde"] } diff --git a/crates/leon-macros/Cargo.toml b/crates/leon-macros/Cargo.toml deleted file mode 100644 index ca4577be..00000000 --- a/crates/leon-macros/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "leon-macros" -version = "1.0.1" -edition = "2021" -description = "Proc macros for crate leon" -repository = "https://github.com/cargo-bins/cargo-binstall" -documentation = "https://docs.rs/leon-macros" -rust-version = "1.61.0" -authors = ["Félix Saparelli ", "Jiahao XU Jiahao_XU@outlook"] -license = "Apache-2.0 OR MIT" - -[lib] -proc-macro = true - -[dependencies] -leon = { version = "3.0.0", path = "../leon", default-features = false } -proc-macro2 = "1.0.68" -syn = { version = "2.0.43", default-features = false, features = ["proc-macro", "parsing"] } -quote = "1.0.28" diff --git a/crates/leon-macros/LICENSE-APACHE b/crates/leon-macros/LICENSE-APACHE deleted file mode 100644 index 1b5ec8b7..00000000 --- a/crates/leon-macros/LICENSE-APACHE +++ /dev/null @@ -1,176 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS diff --git a/crates/leon-macros/LICENSE-MIT b/crates/leon-macros/LICENSE-MIT deleted file mode 100644 index 31aa7938..00000000 --- a/crates/leon-macros/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/crates/leon-macros/src/lib.rs b/crates/leon-macros/src/lib.rs deleted file mode 100644 index 2f6a3389..00000000 --- a/crates/leon-macros/src/lib.rs +++ /dev/null @@ -1,36 +0,0 @@ -use leon::{Item, Template}; -use quote::quote; -use syn::{parse_macro_input, LitStr}; - -#[proc_macro] -pub fn template(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let input = parse_macro_input!(input as LitStr).value(); - - #[allow(clippy::unnecessary_to_owned)] - let items = Template::parse(&input) - .unwrap() - .items - .into_owned() - .into_iter() - .map(|item| match item { - Item::Text(text) => quote! { - ::leon::Item::Text(#text) - }, - Item::Key(key) => quote! { - ::leon::Item::Key(#key) - }, - }); - - quote! { - ::leon::Template::new( - { - const ITEMS: &'static [::leon::Item<'static>] = &[ - #(#items),* - ]; - ITEMS - }, - ::core::option::Option::None, - ) - } - .into() -} diff --git a/crates/leon-macros/tests/parsing.rs b/crates/leon-macros/tests/parsing.rs deleted file mode 100644 index c8dbf8b0..00000000 --- a/crates/leon-macros/tests/parsing.rs +++ /dev/null @@ -1,21 +0,0 @@ -use leon::{Item, Template}; - -#[test] -fn test() { - assert_eq!(leon_macros::template!(""), Template::new(&[], None),); - - assert_eq!( - leon_macros::template!("a"), - Template::new(&[Item::Text("a")], None), - ); - - assert_eq!( - leon_macros::template!("{1}"), - Template::new(&[Item::Key("1")], None), - ); - - assert_eq!( - leon_macros::template!("a{ 1 } c"), - Template::new(&[Item::Text("a"), Item::Key("1"), Item::Text(" c")], None), - ); -} diff --git a/crates/leon/Cargo.toml b/crates/leon/Cargo.toml deleted file mode 100644 index 1a986b9b..00000000 --- a/crates/leon/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "leon" -description = "Dead-simple string templating" -repository = "https://github.com/cargo-bins/cargo-binstall" -documentation = "https://docs.rs/leon" -version = "3.0.0" -rust-version = "1.61.0" -authors = ["Félix Saparelli "] -edition = "2021" -license = "Apache-2.0 OR MIT" -exclude = ["fuzz", "benches"] - -[dependencies] -clap = { version = "4.4.8", features = ["derive"], optional = true } -miette = { version = "7.0.0", default-features = false, features = ["derive"], optional = true } -thiserror = "1.0.52" - -[features] -default = ["miette"] -cli = ["dep:clap", "miette", "miette?/fancy-no-backtrace"] -miette = ["dep:miette"] diff --git a/crates/leon/LICENSE-APACHE b/crates/leon/LICENSE-APACHE deleted file mode 100644 index 1b5ec8b7..00000000 --- a/crates/leon/LICENSE-APACHE +++ /dev/null @@ -1,176 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS diff --git a/crates/leon/LICENSE-MIT b/crates/leon/LICENSE-MIT deleted file mode 100644 index 31aa7938..00000000 --- a/crates/leon/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/crates/leon/benches/.gitignore b/crates/leon/benches/.gitignore deleted file mode 100644 index eb5a316c..00000000 --- a/crates/leon/benches/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target diff --git a/crates/leon/benches/Cargo.lock b/crates/leon/benches/Cargo.lock deleted file mode 100644 index b2fe1571..00000000 --- a/crates/leon/benches/Cargo.lock +++ /dev/null @@ -1,431 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anes" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - -[[package]] -name = "ciborium" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f" -dependencies = [ - "ciborium-io", - "ciborium-ll", - "serde", -] - -[[package]] -name = "ciborium-io" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369" - -[[package]] -name = "ciborium-ll" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b" -dependencies = [ - "ciborium-io", - "half", -] - -[[package]] -name = "clap" -version = "3.2.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" -dependencies = [ - "bitflags", - "clap_lex", - "indexmap", - "textwrap", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "criterion" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" -dependencies = [ - "anes", - "atty", - "cast", - "ciborium", - "clap", - "criterion-plot", - "itertools", - "lazy_static", - "num-traits", - "oorandom", - "regex", - "serde", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-plot" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" -dependencies = [ - "cast", - "itertools", -] - -[[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "half" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "leon" -version = "1.0.0" -dependencies = [ - "miette", - "thiserror", -] - -[[package]] -name = "leon-benches" -version = "0.0.0" -dependencies = [ - "criterion", - "leon", - "serde", - "tinytemplate", -] - -[[package]] -name = "libc" -version = "0.2.142" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" - -[[package]] -name = "miette" -version = "5.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92a992891d5579caa9efd8e601f82e30a1caa79a27a5db075dde30ecb9eab357" -dependencies = [ - "miette-derive", - "once_cell", - "thiserror", - "unicode-width", -] - -[[package]] -name = "miette-derive" -version = "5.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c65c625186a9bcce6699394bee511e1b1aec689aa7e3be1bf4e996e75834153" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" - -[[package]] -name = "oorandom" -version = "11.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" - -[[package]] -name = "os_str_bytes" -version = "6.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" - -[[package]] -name = "proc-macro2" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" - -[[package]] -name = "ryu" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "serde" -version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.96" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "syn" -version = "2.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" - -[[package]] -name = "thiserror" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "unicode-ident" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "walkdir" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/crates/leon/benches/Cargo.toml b/crates/leon/benches/Cargo.toml deleted file mode 100644 index acd07206..00000000 --- a/crates/leon/benches/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "leon-benches" -version = "0.0.0" -publish = false -edition = "2021" - -[dependencies] -leon = { path = ".." } -criterion = { version = "0.4.0", default-features = false, features = ["cargo_bench_support"] } -serde = { version = "1.0.160", features = ["derive"] } -tinytemplate = "1.2.1" - -# Prevent this from interfering with workspaces -[workspace] -members = ["."] - -[[bench]] -name = "values" -harness = false - -[[bench]] -name = "others" -harness = false - -[profile.release] -opt-level = 3 -lto = true -codegen-units = 1 -panic = "abort" -strip = "symbols" diff --git a/crates/leon/benches/benches/others.rs b/crates/leon/benches/benches/others.rs deleted file mode 100644 index 92267a9e..00000000 --- a/crates/leon/benches/benches/others.rs +++ /dev/null @@ -1,89 +0,0 @@ -use std::borrow::Cow; - -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use leon::{vals, Template}; -use serde::Serialize; -use tinytemplate::TinyTemplate; - -fn compare_impls(c: &mut Criterion) { - const TEMPLATE: &str = "hello {name}! i am {age} years old. my goal is to {goal}. i like: {flower}, {music}, {animal}, {color}, {food}. i'm drinking {drink}"; - fn replace_fn(key: &str) -> Option> { - Some(Cow::Borrowed(match key { - "name" => "marcus", - "age" => "42", - "goal" => "primary", - "flower" => "lotus", - "music" => "jazz", - "animal" => "cat", - "color" => "blue", - "food" => "pizza", - "drink" => "coffee", - _ => return None, - })) - } - - #[derive(Copy, Clone, Serialize)] - struct Context<'c> { - name: &'c str, - age: u8, - goal: &'c str, - flower: &'c str, - music: &'c str, - animal: &'c str, - color: &'c str, - food: &'c str, - drink: &'c str, - } - - let tt_context = Context { - name: "marcus", - age: 42, - goal: "primary", - flower: "lotus", - music: "jazz", - animal: "cat", - color: "blue", - food: "pizza", - drink: "coffee", - }; - - c.bench_function("leon", move |b| { - b.iter(move || { - let template = Template::parse(black_box(TEMPLATE)).unwrap(); - let output = template.render(&vals(replace_fn)).unwrap(); - black_box(output); - }) - }); - - c.bench_function("std, string replaces", move |b| { - b.iter(move || { - let mut output = black_box(TEMPLATE).to_string(); - for (key, value) in [ - ("name", "marcus"), - ("age", "42"), - ("goal", "primary"), - ("flower", "lotus"), - ("music", "jazz"), - ("animal", "cat"), - ("color", "blue"), - ("food", "pizza"), - ("drink", "coffee"), - ] { - output = output.replace(&format!("{{{}}}", key), value); - } - black_box(output); - }) - }); - - c.bench_function("tiny template", move |b| { - b.iter(move || { - let mut tt = TinyTemplate::new(); - tt.add_template("tmp", black_box(TEMPLATE)).unwrap(); - let output = tt.render("tmp", &tt_context).unwrap(); - black_box(output); - }) - }); -} - -criterion_group!(compare, compare_impls); -criterion_main!(compare); diff --git a/crates/leon/benches/benches/values.rs b/crates/leon/benches/benches/values.rs deleted file mode 100644 index e2e645bd..00000000 --- a/crates/leon/benches/benches/values.rs +++ /dev/null @@ -1,301 +0,0 @@ -use std::{borrow::Cow, collections::HashMap, sync::Arc}; - -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use leon::{vals, Template, Values, ValuesFn}; - -macro_rules! make_values { - ($($name:expr => $value:expr),*) => { - ( - &[$(($name, $value)),*], - { - let mut map = HashMap::new(); - $( - map.insert($name, $value); - )* - map - }, - vals(|key| match key { - $( - $name => Some(Cow::Borrowed($value)), - )* - _ => None, - }) - ) - }; -} - -fn one_replace(c: &mut Criterion) { - const TEMPLATE: &str = "Hello, {name}!"; - - let (slice, hashmap, vals) = make_values!( - "name" => "marcus" - ); - - inner_bench("one replace", c, TEMPLATE, vals, hashmap, slice); -} - -fn some_replaces(c: &mut Criterion) { - const TEMPLATE: &str = "hello {name}! i am {age} years old. my goal is to {goal}. i like: {flower}, {music}, {animal}, {color}, {food}. i'm drinking {drink}"; - - let (slice, hashmap, vals) = make_values!( - "name" => "marcus", - "age" => "42", - "goal" => "primary", - "flower" => "lotus", - "music" => "jazz", - "animal" => "cat", - "color" => "blue", - "food" => "pizza", - "drink" => "coffee" - ); - - inner_bench("some replaces", c, TEMPLATE, vals, hashmap, slice); -} - -fn many_replaces(c: &mut Criterion) { - const TEMPLATE: &str = " - {artichoke} - {aubergine} - {asparagus} - {broccoflower} - {broccoli} - {brussels sprouts} - {cabbage} - {kohlrabi} - {Savoy cabbage} - {red cabbage} - {cauliflower} - {celery} - {endive} - {fiddleheads} - {frisee} - {fennel} - {greens} - {arugula} - {bok choy} - {chard} - {collard greens} - {kale} - {lettuce} - {mustard greens} - {spinach} - {herbs} - {anise} - {basil} - {caraway} - {coriander} - {chamomile} - {daikon} - {dill} - {squash} - {lavender} - {cymbopogon} - {marjoram} - {oregano} - {parsley} - {rosemary} - {thyme} - {legumes} - {alfalfa sprouts} - {azuki beans} - {bean sprouts} - {black beans} - {black-eyed peas} - {borlotti bean} - {broad beans} - {chickpeas, garbanzos, or ceci beans} - {green beans} - {kidney beans} - {lentils} - {lima beans or butter bean} - {mung beans} - {navy beans} - {peanuts} - {pinto beans} - {runner beans} - {split peas} - {soy beans} - {peas} - {mange tout or snap peas} - {mushrooms} - {nettles} - {New Zealand spinach} - {okra} - {onions} - {chives} - {garlic} - {leek} - {onion} - {shallot} - {scallion} - {peppers} - {bell pepper} - {chili pepper} - {jalapeño} - {habanero} - {paprika} - {tabasco pepper} - {cayenne pepper} - {radicchio} - {rhubarb} - {root vegetables} - {beetroot} - {beet} - {mangelwurzel} - {carrot} - {celeriac} - {corms} - {eddoe} - {konjac} - {taro} - {water chestnut} - {ginger} - {parsnip} - {rutabaga} - {radish} - {wasabi} - "; - - let (slice, hashmap, vals) = make_values!( - "artichoke" => "Abiu", - "aubergine" => "Açaí", - "asparagus" => "Acerola", - "broccoflower" => "Akebi", - "broccoli" => "Ackee", - "brussels sprouts" => "African Cherry Orange", - "cabbage" => "American Mayapple", - "kohlrabi" => "Apple", - "Savoy cabbage" => "Apricot", - "red cabbage" => "Araza", - "cauliflower" => "Avocado", - "celery" => "Banana", - "endive" => "Bilberry", - "fiddleheads" => "Blackberry", - "frisee" => "Blackcurrant", - "fennel" => "Black sapote", - "greens" => "Blueberry", - "arugula" => "Boysenberry", - "bok choy" => "Breadfruit", - "chard" => "Buddha's hand", - "collard greens" => "Cactus pear", - "kale" => "Canistel", - "lettuce" => "Cashew", - "mustard greens" => "Cempedak", - "spinach" => "Cherimoya", - "herbs" => "Cherry", - "anise" => "Chico fruit", - "basil" => "Cloudberry", - "caraway" => "Coco de mer", - "coriander" => "Coconut", - "chamomile" => "Crab apple", - "daikon" => "Cranberry", - "dill" => "Currant", - "squash" => "Damson", - "lavender" => "Date", - "cymbopogon" => "Dragonfruit", - "marjoram" => "Pitaya", - "oregano" => "Durian", - "parsley" => "Elderberry", - "rosemary" => "Feijoa", - "thyme" => "Fig", - "legumes" => "Finger Lime", - "alfalfa sprouts" => "Caviar Lime", - "azuki beans" => "Goji berry", - "bean sprouts" => "Gooseberry", - "black beans" => "Grape", - "black-eyed peas" => "Raisin", - "borlotti bean" => "Grapefruit", - "broad beans" => "Grewia asiatica", - "chickpeas, garbanzos, or ceci beans" => "Guava", - "green beans" => "Hala Fruit", - "kidney beans" => "Honeyberry", - "lentils" => "Huckleberry", - "lima beans or butter bean" => "Jabuticaba", - "mung beans" => "Jackfruit", - "navy beans" => "Jambul", - "peanuts" => "Japanese plum", - "pinto beans" => "Jostaberry", - "runner beans" => "Jujube", - "split peas" => "Juniper berry", - "soy beans" => "Kaffir Lime", - "peas" => "Kiwano", - "mange tout or snap peas" => "Kiwifruit", - "mushrooms" => "Kumquat", - "nettles" => "Lemon", - "New Zealand spinach" => "Lime", - "okra" => "Loganberry", - "onions" => "Longan", - "chives" => "Loquat", - "garlic" => "Lulo", - "leek" => "Lychee", - "onion" => "Magellan Barberry", - "shallot" => "Mamey Apple", - "scallion" => "Mamey Sapote", - "peppers" => "Mango", - "bell pepper" => "Mangosteen", - "chili pepper" => "Marionberry", - "jalapeño" => "Melon", - "habanero" => "Cantaloupe", - "paprika" => "Galia melon", - "tabasco pepper" => "Honeydew", - "cayenne pepper" => "Mouse melon", - "radicchio" => "Musk melon", - "rhubarb" => "Watermelon", - "root vegetables" => "Miracle fruit", - "beetroot" => "Momordica fruit", - "beet" => "Monstera deliciosa", - "mangelwurzel" => "Mulberry", - "carrot" => "Nance", - "celeriac" => "Nectarine", - "corms" => "Orange", - "eddoe" => "Blood orange", - "konjac" => "Clementine", - "taro" => "Mandarine", - "water chestnut" => "Tangerine", - "ginger" => "Papaya", - "parsnip" => "Passionfruit", - "rutabaga" => "Pawpaw", - "radish" => "Peach", - "wasabi" => "Pear" - ); - - inner_bench("many replaces", c, TEMPLATE, vals, hashmap, slice); -} - -fn inner_bench( - name: &str, - c: &mut Criterion, - template_str: &str, - vals: ValuesFn, - hashmap: HashMap<&str, &str>, - slice: &[(&str, &str)], -) where - F: Fn(&str) -> Option> + Send + Clone + 'static, -{ - c.bench_function(&format!("{name}, fn"), move |b| { - let vals = vals.clone(); - b.iter(move || { - let template = Template::parse(black_box(template_str)).unwrap(); - black_box(template.render(&vals).unwrap()); - }) - }); - let hashmap = Arc::new(hashmap); - c.bench_function(&format!("{name}, hashmap"), move |b| { - let hashmap = Arc::clone(&hashmap); - b.iter(move || { - let template = Template::parse(black_box(template_str)).unwrap(); - black_box(template.render(&hashmap).unwrap()); - }) - }); - c.bench_function(&format!("{name}, slice"), move |b| { - b.iter(move || { - let template = Template::parse(black_box(template_str)).unwrap(); - black_box(template.render(&slice as &dyn Values).unwrap()); - }) - }); -} - -criterion_group!(one, one_replace); -criterion_group!(some, some_replaces); -criterion_group!(many, many_replaces); -criterion_main!(one, some, many); diff --git a/crates/leon/benches/src/lib.rs b/crates/leon/benches/src/lib.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/crates/leon/fuzz/.gitignore b/crates/leon/fuzz/.gitignore deleted file mode 100644 index 1a45eee7..00000000 --- a/crates/leon/fuzz/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -target -corpus -artifacts -coverage diff --git a/crates/leon/fuzz/Cargo.lock b/crates/leon/fuzz/Cargo.lock deleted file mode 100644 index 9409a0dd..00000000 --- a/crates/leon/fuzz/Cargo.lock +++ /dev/null @@ -1,150 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "arbitrary" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e90af4de65aa7b293ef2d09daff88501eb254f58edde2e1ac02c82d873eadad" - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" -dependencies = [ - "jobserver", -] - -[[package]] -name = "jobserver" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" -dependencies = [ - "libc", -] - -[[package]] -name = "leon" -version = "0.0.0" -dependencies = [ - "miette", - "thiserror", -] - -[[package]] -name = "leon-fuzz" -version = "0.0.0" -dependencies = [ - "leon", - "libfuzzer-sys", -] - -[[package]] -name = "libc" -version = "0.2.139" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" - -[[package]] -name = "libfuzzer-sys" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beb09950ae85a0a94b27676cccf37da5ff13f27076aa1adbc6545dd0d0e1bd4e" -dependencies = [ - "arbitrary", - "cc", - "once_cell", -] - -[[package]] -name = "miette" -version = "5.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd9b301defa984bbdbe112b4763e093ed191750a0d914a78c1106b2d0fe703" -dependencies = [ - "miette-derive", - "once_cell", - "thiserror", - "unicode-width", -] - -[[package]] -name = "miette-derive" -version = "5.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97c2401ab7ac5282ca5c8b518a87635b1a93762b0b90b9990c509888eeccba29" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "once_cell" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" - -[[package]] -name = "proc-macro2" -version = "1.0.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "syn" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-ident" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" diff --git a/crates/leon/fuzz/Cargo.toml b/crates/leon/fuzz/Cargo.toml deleted file mode 100644 index 1801da08..00000000 --- a/crates/leon/fuzz/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "leon-fuzz" -version = "0.0.0" -publish = false -edition = "2021" - -[package.metadata] -cargo-fuzz = true - -[dependencies] -libfuzzer-sys = "0.4" - -[dependencies.leon] -path = ".." - -# Prevent this from interfering with workspaces -[workspace] -members = ["."] - -[profile.release] -debug = 1 - -[[bin]] -name = "parser" -path = "fuzz_targets/parser.rs" -test = false -doc = false diff --git a/crates/leon/fuzz/fuzz_targets/parser.rs b/crates/leon/fuzz/fuzz_targets/parser.rs deleted file mode 100644 index 9cd51fe5..00000000 --- a/crates/leon/fuzz/fuzz_targets/parser.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![no_main] - -use libfuzzer_sys::fuzz_target; - -fuzz_target!(|data: &[u8]| { - if let Ok(s) = std::str::from_utf8(data) { - let _ = leon::Template::parse(s); - } -}); diff --git a/crates/leon/src/error.rs b/crates/leon/src/error.rs deleted file mode 100644 index 93923cf2..00000000 --- a/crates/leon/src/error.rs +++ /dev/null @@ -1,89 +0,0 @@ -use thiserror::Error as ThisError; - -#[derive(Debug, ThisError)] -#[cfg_attr(feature = "miette", derive(miette::Diagnostic))] -pub enum RenderError { - /// A key was missing from the provided values. - #[error("missing key `{0}`")] - MissingKey(String), - - /// An I/O error passed through from [`Template::render_into`](crate::Template::render_into). - #[error("write failed: {0}")] - Io(#[from] std::io::Error), -} - -/// An error that can occur when parsing a template. -/// -/// When the `miette` feature is enabled, this is a rich miette-powered error -/// which will highlight the source of the error in the template when output -/// (with miette's `fancy` feature). With `miette` disabled, this is opaque. -#[derive(Clone, Debug, ThisError, PartialEq, Eq)] -#[cfg_attr(feature = "miette", derive(miette::Diagnostic))] -#[cfg_attr(feature = "miette", diagnostic(transparent))] -#[error(transparent)] -pub struct ParseError(Box); - -/// The inner (unboxed) type of [`ParseError`]. -#[derive(Clone, Debug, ThisError, PartialEq, Eq)] -#[error("{kind} at span start = {offset}, len = {len}: {src}")] -struct InnerParseError { - src: String, - offset: usize, - len: usize, - kind: ErrorKind, -} - -#[cfg(feature = "miette")] -impl miette::Diagnostic for InnerParseError { - fn source_code(&self) -> Option<&dyn miette::SourceCode> { - Some(&self.src) - } - - fn labels(&self) -> Option + '_>> { - Some(Box::new(std::iter::once_with(|| { - miette::LabeledSpan::new(Some(self.kind.to_string()), self.offset, self.len) - }))) - } -} - -#[derive(Clone, Debug, ThisError, PartialEq, Eq)] -enum ErrorKind { - #[error("This bracket is not opening or closing anything. Try removing it, or escaping it with a backslash.")] - Unbalanced, - - #[error("This escape is malformed.")] - Escape, - - #[error("A key cannot be empty.")] - KeyEmpty, - - #[error("Escapes are not allowed in keys.")] - KeyEscape, -} - -impl ParseError { - fn new(src: &str, start: usize, end: usize, kind: ErrorKind) -> Self { - Self(Box::new(InnerParseError { - src: String::from(src), - offset: start, - len: end.saturating_sub(start) + 1, - kind, - })) - } - - pub(crate) fn unbalanced(src: &str, start: usize, end: usize) -> Self { - Self::new(src, start, end, ErrorKind::Unbalanced) - } - - pub(crate) fn escape(src: &str, start: usize, end: usize) -> Self { - Self::new(src, start, end, ErrorKind::Escape) - } - - pub(crate) fn key_empty(src: &str, start: usize, end: usize) -> Self { - Self::new(src, start, end, ErrorKind::KeyEmpty) - } - - pub(crate) fn key_escape(src: &str, start: usize, end: usize) -> Self { - Self::new(src, start, end, ErrorKind::KeyEscape) - } -} diff --git a/crates/leon/src/lib.rs b/crates/leon/src/lib.rs deleted file mode 100644 index a6ef467e..00000000 --- a/crates/leon/src/lib.rs +++ /dev/null @@ -1,157 +0,0 @@ -//! Dead-simple string templating. -//! -//! Leon parses a template string into a list of tokens, and then substitutes -//! provided values in. Unlike other templating engines, it is extremely simple: -//! it supports no logic, only replaces. It is even simpler than `format!()`, -//! albeit with a similar syntax. -//! -//! # Syntax -//! -//! ```plain -//! it is better to rule { group } -//! one can live {adverb} without power -//! ``` -//! -//! A replacement is denoted by `{` and `}`. The contents of the braces, trimmed -//! of any whitespace, are the key. Any text outside of braces is left as-is. -//! -//! To escape a brace, use `\{` or `\}`. To escape a backslash, use `\\`. Keys -//! cannot contain escapes. -//! -//! ```plain -//! \{ leon \} -//! ``` -//! -//! The above examples, given the values `group = "no one"` and -//! `adverb = "honourably"`, would render to: -//! -//! ```plain -//! it is better to rule no one -//! one can live honourably without power -//! { leon } -//! ``` -//! -//! # Usage -//! -//! A template is first parsed to a token list: -//! -//! ``` -//! use leon::Template; -//! -//! let template = Template::parse("hello {name}").unwrap(); -//! ``` -//! -//! The template can be inspected, for example to check if a key is present: -//! -//! ``` -//! # use leon::Template; -//! # -//! # let template = Template::parse("hello {name}").unwrap(); -//! assert!(template.has_key("name")); -//! ``` -//! -//! The template can be rendered to a string: -//! -//! ``` -//! # use leon::Template; -//! use leon::vals; -//! # -//! # let template = Template::parse("hello {name}").unwrap(); -//! assert_eq!( -//! template.render( -//! &&vals(|_key| Some("marcus".into())) -//! ).unwrap().as_str(), -//! "hello marcus", -//! ); -//! ``` -//! -//! …or to a writer: -//! -//! ``` -//! use std::io::Write; -//! # use leon::Template; -//! use leon::vals; -//! # -//! # let template = Template::parse("hello {name}").unwrap(); -//! let mut buf: Vec = Vec::new(); -//! template.render_into( -//! &mut buf, -//! &&vals(|key| if key == "name" { -//! Some("julius".into()) -//! } else { -//! None -//! }) -//! ).unwrap(); -//! assert_eq!(buf.as_slice(), b"hello julius"); -//! ``` -//! -//! …with a map: -//! -//! ``` -//! use std::collections::HashMap; -//! # use leon::Template; -//! # let template = Template::parse("hello {name}").unwrap(); -//! let mut values = HashMap::new(); -//! values.insert("name", "brutus"); -//! assert_eq!(template.render(&values).unwrap().as_str(), "hello brutus"); -//! ``` -//! -//! …or with your own type, if you implement the [`Values`] trait: -//! -//! ``` -//! # use leon::Template; -//! use std::borrow::Cow; -//! use leon::Values; -//! -//! struct MyMap { -//! name: &'static str, -//! } -//! impl Values for MyMap { -//! fn get_value(&self, key: &str) -> Option> { -//! if key == "name" { -//! Some(self.name.into()) -//! } else { -//! None -//! } -//! } -//! } -//! # -//! # let template = Template::parse("hello {name}").unwrap(); -//! let values = MyMap { name: "pontifex" }; -//! assert_eq!(template.render(&values).unwrap().as_str(), "hello pontifex"); -//! ``` -//! -//! # Compile-time parsing -//! -//! You can either use [`leon-macros`](https://docs.rs/leon-macros)'s -//! [`template!`](https://docs.rs/leon-macros/latest/leon_macros/macro.template.html), -//! a proc-macro, with the exact same syntax as the normal parser, or this -//! crate's [`template!`] rules-macro, which requires a slightly different -//! syntax but doesn't bring in additional dependencies. In either case, -//! the leon library is required as a runtime dependency. -//! -//! # Errors -//! -//! Leon will return a [`ParseError`] if the template fails to -//! parse. This can happen if there are unbalanced braces, or if a key is empty. -//! -//! Leon will return a [`RenderError::MissingKey`] if a key is missing from keyed -//! values passed to [`Template::render()`], unless a default value is provided -//! with [`Template.default`]. -//! -//! It will also pass through I/O errors when using [`Template::render_into()`]. - -#[doc(inline)] -pub use error::*; - -#[doc(inline)] -pub use template::*; - -#[doc(inline)] -pub use values::*; - -mod error; -mod macros; -mod parser; -mod template; -mod values; diff --git a/crates/leon/src/macros.rs b/crates/leon/src/macros.rs deleted file mode 100644 index 1de4fda6..00000000 --- a/crates/leon/src/macros.rs +++ /dev/null @@ -1,156 +0,0 @@ -#[doc(hidden)] -#[macro_export] -macro_rules! __template_item { - () => {}; - ({ $key:literal }) => { - $crate::Item::Key($key) - }; - ( $text:literal ) => { - $crate::Item::Text($text) - }; -} - -#[doc(hidden)] -#[macro_export] -macro_rules! __template_impl { - ($( $token:tt ),* ; $default:expr) => { - $crate::Template::new( - { - const ITEMS: &'static [$crate::Item<'static>] = &[ - $( - $crate::__template_item!($token) - ),* - ]; - ITEMS - }, - $default, - ) - }; -} - -/// Construct a template constant using syntax similar to the template to be -/// passed to [`Template::parse`](crate::Template::parse). -/// -/// This is essentially a shorthand for: -/// -/// ``` -/// use leon::{Item, Template}; -/// Template::new({ -/// const ITEMS: &'static [Item<'static>] = &[Item::Text("Hello "), Item::Key("name")]; -/// ITEMS -/// }, Some("world")); -/// ``` -/// -/// # Examples -/// -/// ``` -/// assert_eq!( -/// leon::template!("Hello ", {"name"}) -/// .render(&[("name", "Магда Нахман")]) -/// .unwrap(), -/// "Hello Магда Нахман", -/// ); -/// ``` -/// -/// With a default: -/// -/// ``` -/// assert_eq!( -/// leon::template!("Hello ", {"name"}; "M. P. T. Acharya") -/// .render(&[("city", "Madras")]) -/// .unwrap(), -/// "Hello M. P. T. Acharya", -/// ); -/// ``` -#[macro_export] -macro_rules! template { - () => { - $crate::Template::new( - { - const ITEMS: &'static [$crate::Item<'static>] = &[]; - ITEMS - }, - ::core::option::Option::None, - ) - }; - - ($( $token:tt ),* $(,)?) => { - $crate::__template_impl!($( $token ),* ; ::core::option::Option::None) - }; - - ($( $token:tt ),* $(,)? ; $default:expr) => { - $crate::__template_impl!($( $token ),* ; ::core::option::Option::Some($default)) - }; -} - -#[cfg(test)] -mod tests { - use crate::{template, Item, Template}; - - #[test] - fn test_template2() { - assert_eq!(template!(), Template::new(&[], None),); - - // Only literals - assert_eq!(template!("1"), Template::new(&[Item::Text("1")], None)); - - assert_eq!( - template!("1", "2"), - Template::new(&[Item::Text("1"), Item::Text("2")], None) - ); - - assert_eq!( - template!("1", "2", "3"), - Template::new(&[Item::Text("1"), Item::Text("2"), Item::Text("3")], None) - ); - - // Only keys - assert_eq!(template!({ "k1" }), Template::new(&[Item::Key("k1")], None)); - - assert_eq!( - template!({ "k1" }, { "k2" }), - Template::new(&[Item::Key("k1"), Item::Key("k2")], None) - ); - - assert_eq!( - template!({ "k1" }, { "k2" }, { "k3" }), - Template::new(&[Item::Key("k1"), Item::Key("k2"), Item::Key("k3")], None) - ); - - // Mixed - assert_eq!( - template!("1", { "k1" }, "3"), - Template::new(&[Item::Text("1"), Item::Key("k1"), Item::Text("3")], None) - ); - - assert_eq!( - template!("1", "2", { "k1" }, "3", "4"), - Template::new( - &[ - Item::Text("1"), - Item::Text("2"), - Item::Key("k1"), - Item::Text("3"), - Item::Text("4") - ], - None - ) - ); - - assert_eq!( - template!("1", "2", { "k1" }, { "k2" }, "3", "4", { "k3" }), - Template::new( - &[ - Item::Text("1"), - Item::Text("2"), - Item::Key("k1"), - Item::Key("k2"), - Item::Text("3"), - Item::Text("4"), - Item::Key("k3"), - ], - None - ) - ); - } -} diff --git a/crates/leon/src/main.rs b/crates/leon/src/main.rs deleted file mode 100644 index acbdb1f5..00000000 --- a/crates/leon/src/main.rs +++ /dev/null @@ -1,61 +0,0 @@ -#[cfg(feature = "cli")] -fn main() -> miette::Result<()> { - use std::{collections::HashMap, error::Error, io::stdout}; - - use clap::Parser; - use leon::Template; - - /// Render a Leon template with the given values. - #[derive(Parser, Debug)] - #[command(author, version, about, long_about = None)] - struct Args { - /// Leon template - template: String, - - /// Default to use for missing keys - #[arg(long)] - default: Option, - - /// Use values from the environment - #[arg(long)] - env: bool, - - /// Key-value pairs to use - #[arg(short, long, value_parser = parse_key_val::)] - values: Vec<(String, String)>, - } - - /// Parse a single key-value pair - fn parse_key_val(s: &str) -> Result<(T, U), Box> - where - T: std::str::FromStr, - T::Err: Error + Send + Sync + 'static, - U: std::str::FromStr, - U::Err: Error + Send + Sync + 'static, - { - let (k, v) = s - .split_once('=') - .ok_or_else(|| format!("invalid KEY=value: no `=` found in `{s}`"))?; - Ok((k.parse()?, v.parse()?)) - } - - let args = Args::parse(); - let mut values: HashMap = HashMap::from_iter(args.values); - if args.env { - for (key, value) in std::env::vars() { - values.entry(key).or_insert(value); - } - } - - let template = args.template; - let mut template = Template::parse(&template)?; - if let Some(default) = &args.default { - template.set_default(default); - } - - template.render_into(&mut stdout().lock(), &values)?; - Ok(()) -} - -#[cfg(not(feature = "cli"))] -fn main() {} diff --git a/crates/leon/src/parser.rs b/crates/leon/src/parser.rs deleted file mode 100644 index 7c033cba..00000000 --- a/crates/leon/src/parser.rs +++ /dev/null @@ -1,334 +0,0 @@ -use crate::{Item, ParseError, Template}; - -impl<'s> Template<'s> { - pub(crate) fn parse_items(source: &'s str) -> Result>, ParseError> { - let mut items = Vec::new(); - - let mut start = 0; - let mut s = source; - - loop { - if let Some(index) = s.find(['\\', '{', '}']) { - if index != 0 { - let (first, last) = s.split_at(index); - items.push(Item::Text(first)); - - // Move cursor forward - start += index; - s = last; - } - } else { - if !s.is_empty() { - items.push(Item::Text(s)); - } - - break Ok(items); - }; - - let mut chars = s.chars(); - let ch = chars.next().unwrap(); - - match ch { - '\\' => { - match chars.next() { - Some('\\' | '{' | '}') => { - let t = s.get(1..2).unwrap(); - debug_assert!(["\\", "{", "}"].contains(&t), "{}", t); - items.push(Item::Text(t)); - - // Move cursor forward - start += 2; - s = s.get(2..).unwrap(); - } - _ => { - return Err(ParseError::escape(source, start, start + 1)); - } - } - } - '{' => { - let Some((key, rest)) = s[1..].split_once('}') else { - return Err(ParseError::unbalanced(source, start, start + s.len())); - }; - if let Some(index) = key.find('\\') { - return Err(ParseError::key_escape(source, start, start + 1 + index)); - } - - let k = key.trim(); - if k.is_empty() { - return Err(ParseError::key_empty(source, start, start + key.len() + 1)); - } - items.push(Item::Key(k)); - - // Move cursor forward - // for the '{' - // | for the '}' - // | | - start += 1 + key.len() + 1; - s = rest; - } - '}' => { - return Err(ParseError::unbalanced(source, start, start)); - } - _ => unreachable!(), - } - } - } -} - -#[cfg(test)] -mod test_valid { - use crate::{template, Template}; - - #[test] - fn empty() { - let template = Template::parse("").unwrap(); - assert_eq!(template, Template::default()); - } - - #[test] - fn no_keys() { - let template = Template::parse("hello world").unwrap(); - assert_eq!(template, template!("hello world")); - } - - #[test] - fn leading_key() { - let template = Template::parse("{salutation} world").unwrap(); - assert_eq!(template, template!({ "salutation" }, " world")); - } - - #[test] - fn trailing_key() { - let template = Template::parse("hello {name}").unwrap(); - assert_eq!(template, template!("hello ", { "name" })); - } - - #[test] - fn middle_key() { - let template = Template::parse("hello {name}!").unwrap(); - assert_eq!(template, template!("hello ", { "name" }, "!")); - } - - #[test] - fn middle_text() { - let template = Template::parse("{salutation} good {title}").unwrap(); - assert_eq!(template, template!({ "salutation" }, " good ", { "title" })); - } - - #[test] - fn multiline() { - let template = Template::parse( - " - And if thy native country was { ancient civilisation }, - What need to slight thee? Came not {hero} thence, - Who gave to { country } her books and art of writing? - ", - ) - .unwrap(); - assert_eq!( - template, - template!( - "\n And if thy native country was ", - { "ancient civilisation" }, - ",\n What need to slight thee? Came not ", - { "hero" }, - " thence,\n Who gave to ", - { "country" }, - " her books and art of writing?\n ", - ) - ); - } - - #[test] - fn key_no_whitespace() { - let template = Template::parse("{word}").unwrap(); - assert_eq!(template, template!({ "word" })); - } - - #[test] - fn key_leading_whitespace() { - let template = Template::parse("{ word}").unwrap(); - assert_eq!(template, template!({ "word" })); - } - - #[test] - fn key_trailing_whitespace() { - let template = Template::parse("{word\n}").unwrap(); - assert_eq!(template, template!({ "word" })); - } - - #[test] - fn key_both_whitespace() { - let template = Template::parse( - "{ - \tword - }", - ) - .unwrap(); - assert_eq!(template, template!({ "word" })); - } - - #[test] - fn key_inner_whitespace() { - let template = Template::parse("{ a word }").unwrap(); - assert_eq!(template, template!({ "a word" })); - } - - #[test] - fn escape_left() { - let template = Template::parse(r"this \{ single left brace").unwrap(); - assert_eq!(template, template!("this ", "{", " single left brace")); - } - - #[test] - fn escape_right() { - let template = Template::parse(r"this \} single right brace").unwrap(); - assert_eq!(template, template!("this ", "}", " single right brace")); - } - - #[test] - fn escape_both() { - let template = Template::parse(r"these \{ two \} braces").unwrap(); - assert_eq!(template, template!("these ", "{", " two ", "}", " braces")); - } - - #[test] - fn escape_doubled() { - let template = Template::parse(r"these \{\{ four \}\} braces").unwrap(); - assert_eq!( - template, - template!("these ", "{", "{", " four ", "}", "}", " braces") - ); - } - - #[test] - fn escape_escape() { - let template = Template::parse(r"these \\ backslashes \\\\").unwrap(); - assert_eq!( - template, - template!("these ", r"\", " backslashes ", r"\", r"\",) - ); - } - - #[test] - fn escape_before_key() { - let template = Template::parse(r"\\{ a } \{{ b } \}{ c }").unwrap(); - assert_eq!( - template, - template!(r"\", { "a" }, " ", r"{", { "b" }, " ", r"}", { "c" }) - ); - } - - #[test] - fn escape_after_key() { - let template = Template::parse(r"{ a }\\ { b }\{ { c }\}").unwrap(); - assert_eq!( - template, - template!({ "a" }, r"\", " ", { "b" }, r"{", " ", { "c" }, r"}") - ); - } - - #[test] - fn multibyte_texts() { - let template = Template::parse("幸徳 {particle} 秋水").unwrap(); - assert_eq!(template, template!("幸徳 ", { "particle" }, " 秋水")); - } - - #[test] - fn multibyte_key() { - let template = Template::parse("The { 連盟 }").unwrap(); - assert_eq!(template, template!("The ", { "連盟" })); - } - - #[test] - fn multibyte_both() { - let template = Template::parse("大杉 {栄}").unwrap(); - assert_eq!(template, template!("大杉 ", { "栄" })); - } - - #[test] - fn multibyte_whitespace() { - let template = Template::parse("岩佐 作{ 太 }郎").unwrap(); - assert_eq!(template, template!("岩佐 作", { "太" }, "郎")); - } - - #[test] - fn multibyte_with_escapes() { - let template = Template::parse(r"日本\{アナキスト\}連盟").unwrap(); - assert_eq!( - template, - template!("日本", r"{", "アナキスト", r"}", "連盟") - ); - } - - #[test] - fn multibyte_rtl_text() { - let template = Template::parse("محمد صايل").unwrap(); - assert_eq!(template, template!("محمد صايل")); - } - - #[test] - fn multibyte_rtl_key() { - let template = Template::parse("محمد {ريشة}").unwrap(); - assert_eq!(template, template!("محمد ", { "ريشة" })); - } -} - -#[cfg(test)] -mod test_error { - use crate::{ParseError, Template}; - - #[test] - fn key_left_half() { - let template = Template::parse("{ open").unwrap_err(); - assert_eq!(template, ParseError::unbalanced("{ open", 0, 6)); - } - - #[test] - fn key_right_half() { - let template = Template::parse("open }").unwrap_err(); - assert_eq!(template, ParseError::unbalanced("open }", 5, 5)); - } - - #[test] - fn key_with_half_escape() { - let template = Template::parse(r"this is { not \ allowed }").unwrap_err(); - assert_eq!( - template, - ParseError::key_escape(r"this is { not \ allowed }", 8, 14) - ); - } - - #[test] - fn key_with_full_escape() { - let template = Template::parse(r"{ not \} allowed }").unwrap_err(); - assert_eq!( - template, - ParseError::key_escape(r"{ not \} allowed }", 0, 6) - ); - } - - #[test] - fn key_empty() { - let template = Template::parse(r"void: {}").unwrap_err(); - assert_eq!(template, ParseError::key_empty(r"void: {}", 6, 7)); - } - - #[test] - fn key_only_whitespace() { - let template = Template::parse(r"nothing: { }").unwrap_err(); - assert_eq!(template, ParseError::key_empty(r"nothing: { }", 9, 11)); - } - - #[test] - fn bad_escape() { - let template = Template::parse(r"not \a thing").unwrap_err(); - assert_eq!(template, ParseError::escape(r"not \a thing", 4, 5)); - } - - #[test] - fn end_escape() { - let template = Template::parse(r"forget me not \").unwrap_err(); - assert_eq!(template, ParseError::escape(r"forget me not \", 14, 15)); - } -} diff --git a/crates/leon/src/template.rs b/crates/leon/src/template.rs deleted file mode 100644 index e24b8aca..00000000 --- a/crates/leon/src/template.rs +++ /dev/null @@ -1,278 +0,0 @@ -use std::{borrow::Cow, fmt::Display, io::Write, ops}; - -use crate::{ParseError, RenderError, Values}; - -#[derive(Clone, Debug, Default, PartialEq, Eq)] -pub struct Template<'s> { - pub items: Cow<'s, [Item<'s>]>, - pub default: Option>, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Item<'s> { - Text(&'s str), - Key(&'s str), -} - -impl<'s> Template<'s> { - /// Construct a template with the given items and default. - /// - /// You can write a template literal without any help by constructing it directly: - /// - /// ``` - /// use std::borrow::Cow; - /// use leon::{Item, Template}; - /// const TEMPLATE: Template = Template { - /// items: Cow::Borrowed({ - /// const ITEMS: &'static [Item<'static>] = &[ - /// Item::Text("Hello"), - /// Item::Key("name"), - /// ]; - /// ITEMS - /// }), - /// default: None, - /// }; - /// assert_eq!(TEMPLATE.render(&[("name", "world")]).unwrap(), "Helloworld"); - /// ``` - /// - /// As that's a bit verbose, using this function and the enum shorthands can be helpful: - /// - /// ``` - /// use leon::{Item, Item::*, Template}; - /// const TEMPLATE: Template = Template::new({ - /// const ITEMS: &'static [Item<'static>] = &[Text("Hello "), Key("name")]; - /// ITEMS - /// }, Some("world")); - /// - /// assert_eq!(TEMPLATE.render(&[("unrelated", "value")]).unwrap(), "Hello world"); - /// ``` - /// - /// For an even more ergonomic syntax, see the [`leon::template!`](crate::template!) macro. - pub const fn new(items: &'s [Item<'s>], default: Option<&'s str>) -> Template<'s> { - Template { - items: Cow::Borrowed(items), - default: match default { - Some(default) => Some(Cow::Borrowed(default)), - None => None, - }, - } - } - - /// Parse a template from a string. - /// - /// # Syntax - /// - /// ```plain - /// it is better to rule { group } - /// one can live {adverb} without power - /// ``` - /// - /// A replacement is denoted by `{` and `}`. The contents of the braces, trimmed - /// of any whitespace, are the key. Any text outside of braces is left as-is. - /// - /// To escape a brace, use `\{` or `\}`. To escape a backslash, use `\\`. Keys - /// cannot contain escapes. - /// - /// ```plain - /// \{ leon \} - /// ``` - /// - /// The above examples, given the values `group = "no one"` and - /// `adverb = "honourably"`, would render to: - /// - /// ```plain - /// it is better to rule no one - /// one can live honourably without power - /// { leon } - /// ``` - /// - /// # Example - /// - /// ``` - /// use leon::Template; - /// let template = Template::parse("hello {name}").unwrap(); - /// ``` - /// - pub fn parse(s: &'s str) -> Result { - Self::parse_items(s).map(|items| Template { - items: Cow::Owned(items), - default: None, - }) - } - - pub fn render_into( - &self, - writer: &mut dyn Write, - values: &dyn Values, - ) -> Result<(), RenderError> { - for token in self.items.as_ref() { - match token { - Item::Text(text) => writer.write_all(text.as_bytes())?, - Item::Key(key) => { - if let Some(value) = values.get_value(key) { - writer.write_all(value.as_bytes())?; - } else if let Some(default) = &self.default { - writer.write_all(default.as_bytes())?; - } else { - return Err(RenderError::MissingKey(key.to_string())); - } - } - } - } - Ok(()) - } - - pub fn render(&self, values: &dyn Values) -> Result { - let mut buf = Vec::with_capacity( - self.items - .iter() - .map(|item| match item { - Item::Key(_) => 0, - Item::Text(t) => t.len(), - }) - .sum(), - ); - self.render_into(&mut buf, values)?; - - // UNWRAP: We know that the buffer is valid UTF-8 because we only write strings. - Ok(String::from_utf8(buf).unwrap()) - } - - /// If the template contains key `key`. - pub fn has_key(&self, key: &str) -> bool { - self.has_any_of_keys(&[key]) - } - - /// If the template contains any one of the `keys`. - pub fn has_any_of_keys(&self, keys: &[&str]) -> bool { - self.items.iter().any(|token| match token { - Item::Key(k) => keys.contains(k), - _ => false, - }) - } - - /// Returns all keys in this template. - pub fn keys(&self) -> impl Iterator { - self.items.iter().filter_map(|token| match token { - Item::Key(k) => Some(k), - _ => None, - }) - } - - /// Sets the default value for this template. - pub fn set_default(&mut self, default: &dyn Display) { - self.default = Some(Cow::Owned(default.to_string())); - } - - /// Cast `Template<'s>` to `Template<'t>` where `'s` is a subtype of `'t`, - /// meaning that `Template<'s>` outlives `Template<'t>`. - pub fn cast<'t>(self) -> Template<'t> - where - 's: 't, - { - Template { - items: match self.items { - Cow::Owned(vec) => Cow::Owned(vec), - Cow::Borrowed(slice) => Cow::Borrowed(slice as &'t [Item<'t>]), - }, - default: self.default.map(|default| default as Cow<'t, str>), - } - } -} - -impl<'s, 'rhs: 's> ops::AddAssign<&Template<'rhs>> for Template<'s> { - fn add_assign(&mut self, rhs: &Template<'rhs>) { - self.items - .to_mut() - .extend(rhs.items.as_ref().iter().cloned()); - - if let Some(default) = &rhs.default { - self.default = Some(default.clone()); - } - } -} - -impl<'s, 'rhs: 's> ops::AddAssign> for Template<'s> { - fn add_assign(&mut self, rhs: Template<'rhs>) { - match rhs.items { - Cow::Borrowed(items) => self.items.to_mut().extend(items.iter().cloned()), - Cow::Owned(items) => self.items.to_mut().extend(items), - } - - if let Some(default) = rhs.default { - self.default = Some(default); - } - } -} - -impl<'s, 'item: 's> ops::AddAssign> for Template<'s> { - fn add_assign(&mut self, item: Item<'item>) { - self.items.to_mut().push(item); - } -} - -impl<'s, 'item: 's> ops::AddAssign<&Item<'item>> for Template<'s> { - fn add_assign(&mut self, item: &Item<'item>) { - self.add_assign(item.clone()) - } -} - -impl<'s, 'rhs: 's> ops::Add> for Template<'s> { - type Output = Self; - - fn add(mut self, rhs: Template<'rhs>) -> Self::Output { - self += rhs; - self - } -} - -impl<'s, 'rhs: 's> ops::Add<&Template<'rhs>> for Template<'s> { - type Output = Self; - - fn add(mut self, rhs: &Template<'rhs>) -> Self::Output { - self += rhs; - self - } -} - -impl<'s, 'item: 's> ops::Add> for Template<'s> { - type Output = Self; - - fn add(mut self, item: Item<'item>) -> Self::Output { - self += item; - self - } -} - -impl<'s, 'item: 's> ops::Add<&Item<'item>> for Template<'s> { - type Output = Self; - - fn add(mut self, item: &Item<'item>) -> Self::Output { - self += item; - self - } -} - -#[cfg(test)] -mod test { - use crate::Template; - - #[test] - fn concat_templates() { - let t1 = crate::template!("Hello", { "name" }); - let t2 = crate::template!("have a", { "adjective" }, "day"); - assert_eq!( - t1 + t2, - crate::template!("Hello", { "name" }, "have a", { "adjective" }, "day"), - ); - } - - #[test] - fn test_cast() { - fn inner<'a>(_: &'a u32, _: Template<'a>) {} - - let template: Template<'static> = crate::template!("hello"); - let i = 1; - inner(&i, template.cast()); - } -} diff --git a/crates/leon/src/values.rs b/crates/leon/src/values.rs deleted file mode 100644 index f5255272..00000000 --- a/crates/leon/src/values.rs +++ /dev/null @@ -1,161 +0,0 @@ -use std::{ - borrow::{Borrow, Cow}, - collections::{BTreeMap, HashMap}, - hash::{BuildHasher, Hash}, - ops::Deref, - rc::Rc, - sync::Arc, -}; - -pub trait Values { - fn get_value(&self, key: &str) -> Option>; -} - -impl Values for &T -where - T: Values, -{ - fn get_value(&self, key: &str) -> Option> { - T::get_value(self, key) - } -} - -impl Values for Arc -where - T: Values, -{ - fn get_value(&self, key: &str) -> Option> { - T::get_value(self.deref(), key) - } -} - -impl Values for Rc -where - T: Values, -{ - fn get_value(&self, key: &str) -> Option> { - T::get_value(self.deref(), key) - } -} - -impl Values for [(K, V)] -where - K: AsRef, - V: AsRef, -{ - fn get_value(&self, key: &str) -> Option> { - self.iter().find_map(|(k, v)| { - if k.as_ref() == key { - Some(Cow::Borrowed(v.as_ref())) - } else { - None - } - }) - } -} - -impl Values for &[(K, V)] -where - K: AsRef, - V: AsRef, -{ - fn get_value(&self, key: &str) -> Option> { - (*self).get_value(key) - } -} - -impl Values for [(K, V); N] -where - K: AsRef, - V: AsRef, -{ - fn get_value(&self, key: &str) -> Option> { - self.as_slice().get_value(key) - } -} - -impl Values for Vec<(K, V)> -where - K: AsRef, - V: AsRef, -{ - fn get_value(&self, key: &str) -> Option> { - self.as_slice().get_value(key) - } -} - -impl Values for HashMap -where - K: Borrow + Eq + Hash, - V: AsRef, - S: BuildHasher, -{ - fn get_value(&self, key: &str) -> Option> { - self.get(key).map(|v| Cow::Borrowed(v.as_ref())) - } -} - -impl Values for BTreeMap -where - K: Borrow + Ord, - V: AsRef, -{ - fn get_value(&self, key: &str) -> Option> { - self.get(key).map(|v| Cow::Borrowed(v.as_ref())) - } -} - -/// Workaround to allow using functions as [`Values`]. -/// -/// As this isn't constructible you'll want to use [`vals()`] instead. -#[derive(Copy, Clone, Debug)] -pub struct ValuesFn { - inner: F, -} - -impl Values for ValuesFn -where - F: Fn(&str) -> Option>, -{ - fn get_value(&self, key: &str) -> Option> { - (self.inner)(key) - } -} - -/// See doc of [`vals`] -impl From for ValuesFn -where - F: Fn(&str) -> Option>, -{ - fn from(inner: F) -> Self { - Self { inner } - } -} - -/// Wraps your function so it implements [`Values`], -/// though it only works if your function returns `Cow<'static, str>`. -/// -/// Since regular function pointers cannot return anything other than -/// `Cow<'static, str>` and closure in Rust currently does not support -/// returning borrows of captured data, supporting anything other than -/// `Cow<'static, str>` for functions is pointless and would only cause -/// more confusion and compile-time errors. -/// -/// To return `&str` owned by the values itself, please create a newtype -/// and implement [`Values`] on it manually instead of using this function. -/// -/// # Example -/// -/// ``` -/// use leon::{Values, vals}; -/// -/// fn use_values(_values: impl Values) {} -/// -/// use_values(&vals(|_| Some("hello".into()))); -/// ``` -pub const fn vals(func: F) -> ValuesFn -where - F: Fn(&str) -> Option>, -{ - ValuesFn { inner: func } -} diff --git a/justfile b/justfile index 46f5c8ec..d01a9510 100644 --- a/justfile +++ b/justfile @@ -215,7 +215,6 @@ build: print-env check: print-env {{cargo-bin}} check {{cargo-build-args}} --profile check-only - cargo hack check --feature-powerset -p leon {{cargo-check-args}} --profile check-only {{cargo-bin}} check -p binstalk-downloader --no-default-features --profile check-only {{cargo-bin}} check -p cargo-binstall --no-default-features --features rustls {{cargo-check-args}} --profile check-only cargo-hack hack check -p binstalk-downloader \