From 15f3a4b8a6125e5290215556fcfd9909ee812577 Mon Sep 17 00:00:00 2001 From: nils <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 17 Jul 2021 23:25:44 +0200 Subject: [PATCH 01/28] Create LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f1754b8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 nilstrieb + +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. From 7065de15e4d9e43d2522b75f6f9de95d514d2891 Mon Sep 17 00:00:00 2001 From: nils <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 17 Jul 2021 23:37:34 +0200 Subject: [PATCH 02/28] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 71dbfab..0e15133 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,10 @@ OPTIONS: -o, --output The output file for the formatted json ``` +Reads from stdin if no file is supplied. +Outputs to stdout if no output file is specified. + ## How? `jsonformat` does not actually parse the json, it just loops through each characters and keeps track of some flags. It then copies these characters to the output buffer, adding and removing whitespace. -The code is currently a bit chaotic, but it works and is fast, so good enough for now. Maybe it could profit from SIMD in the future, but I have never used it and I don't know whether it would work. Maybe some day... \ No newline at end of file +The code is currently a bit chaotic, but it works and is fast, so good enough for now. Maybe it could profit from SIMD in the future, but I have never used it and I don't know whether it would work. Maybe some day... From 5eed9d0815530377a6963056ee3c08e1a0bd3fc6 Mon Sep 17 00:00:00 2001 From: nils <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 17 Jul 2021 23:42:37 +0200 Subject: [PATCH 03/28] typo in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e15133..9f9bbc5 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,6 @@ Reads from stdin if no file is supplied. Outputs to stdout if no output file is specified. ## How? -`jsonformat` does not actually parse the json, it just loops through each characters and keeps track of some flags. It then copies these characters to the output buffer, adding and removing whitespace. +`jsonformat` does not actually parse the json, it just loops through each character and keeps track of some flags. It then copies these characters to the output buffer, adding and removing whitespace. The code is currently a bit chaotic, but it works and is fast, so good enough for now. Maybe it could profit from SIMD in the future, but I have never used it and I don't know whether it would work. Maybe some day... From 8a1da052bf7b0546bb24c21d4c47b84e58b17b5a Mon Sep 17 00:00:00 2001 From: Nilstrieb Date: Sun, 18 Jul 2021 11:00:21 +0200 Subject: [PATCH 04/28] fix #2 indentation_level underflow --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 35a4e71..6479e41 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ pub fn format_json(json: &str, indentation: Option<&str>) -> String { let mut escaped = false; let mut in_string = false; - let mut indent_level = 0; + let mut indent_level = 0usize; let mut newline_requested = false; // invalidated if next character is ] or } for char in json.chars() { @@ -50,7 +50,7 @@ pub fn format_json(json: &str, indentation: Option<&str>) -> String { request_newline = true; } '}' | ']' => { - indent_level -= 1; + indent_level = indent_level.saturating_sub(1); if !newline_requested { // see comment below about newline_requested out.push('\n'); From 3db3d1996ea568e657a7b87ee80b084d9f785764 Mon Sep 17 00:00:00 2001 From: Nilstrieb Date: Sun, 18 Jul 2021 11:54:17 +0200 Subject: [PATCH 05/28] add new test --- src/lib.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 6479e41..22e4aab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -165,4 +165,19 @@ mod test { assert_eq!(expected, format_json(json, None)); } + + #[test] + fn already_formatted() { + let expected = "[ + { + \"a\": 0 + }, + {}, + { + \"a\": null + } +]"; + + assert_eq!(expected, format_json(expected, None)); + } } From b254431128146a872c247397ba4a5aafa0f69da3 Mon Sep 17 00:00:00 2001 From: Nilstrieb Date: Sun, 18 Jul 2021 11:56:01 +0200 Subject: [PATCH 06/28] added #3 support drag and drop in windows --- README.md | 6 ++++++ src/main.rs | 19 +++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9f9bbc5..6782992 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,12 @@ OPTIONS: Reads from stdin if no file is supplied. Outputs to stdout if no output file is specified. +On windows, it writes to a file called `_f.json`, unless the `--stdout` flag is used or a custom output file is provided. This it to enable drag-and-drop in windows explorer. + +## Error handling +`jsonformat` does not report malformed json - it can't even fully know whether the json is actually malformed. Malformed json is just formatted kind of incorrectly, with no data lost and no crashes. If you find one, open an issue, + + ## How? `jsonformat` does not actually parse the json, it just loops through each character and keeps track of some flags. It then copies these characters to the output buffer, adding and removing whitespace. diff --git a/src/main.rs b/src/main.rs index 5749763..501a4c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,9 +6,10 @@ use std::io::Read; fn main() -> Result<(), io::Error> { let matches = clap_app!(jsonformat => - (version: "1.0") + (version: "1.1") (author: "nilstrieb ") (about: "Formats json from stdin or from a file") + (@arg stdout: -s --stdout "Output the result to stdout instead of the default output file. Windows only.") (@arg indentation: -i --indent +takes_value "Set the indentation used (\\s for space, \\t for tab)") (@arg output: -o --output +takes_value "The output file for the formatted json") (@arg input: "The input file to format") @@ -37,7 +38,21 @@ fn main() -> Result<(), io::Error> { let formatted = format_json(&str, replaced_indent.as_deref()); - match matches.value_of("output") { + let mut output = matches.value_of("output"); + let mut windows_output_default_file: Option = None; + + #[cfg(windows)] + if !matches.is_present("stdout") { + if let Some(file) = matches.value_of("input") { + // on windows, set the default output file if no stdout flag is provided + // this makes it work with drag and drop in windows explorer + windows_output_default_file = Some(file.replace(".json", "_f.json")) + } + } + + output = windows_output_default_file.as_deref().or(output); + + match output { Some(file) => { fs::write(file, formatted)?; } From 4df1c18504df7b4ce4b1765652aa9241efe20515 Mon Sep 17 00:00:00 2001 From: Nilstrieb Date: Wed, 18 Aug 2021 19:01:57 +0200 Subject: [PATCH 07/28] ready for publishing --- Cargo.toml | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c6bf827..dd5b306 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,16 +3,35 @@ name = "jsonformat" version = "0.1.0" authors = ["Nilstrieb "] edition = "2018" -description = "Reads raw json from stdin and formats it to stdout" +license = "MIT" +description = "Formats JSON extremely fast" +homepage = "https://github.com/Nilstrieb/jsonformat" +repository = "https://github.com/Nilstrieb/jsonformat" +readme = "README.md" +keywords = ["json", "formatting", "cli"] +categories = ["command-line-utilities"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = "3.0.0-beta.2" +clap = { version= "3.0.0-beta.2", optional = true } [dev-dependencies] criterion = "0.3" +[features] +default = ["bin"] +bin = ["clap"] + +[lib] +name = "jsonformat" +path = "src/lib.rs" + +[[bin]] +name = "jsonformat" +path = "src/main.rs" +required-features = ["bin"] + [[bench]] name = "bench" harness = false \ No newline at end of file From ed052dd70a1b6922d4fd19a874eba54995320672 Mon Sep 17 00:00:00 2001 From: Nilstrieb Date: Wed, 18 Aug 2021 19:16:16 +0200 Subject: [PATCH 08/28] change the api --- Cargo.lock | 2 +- Cargo.toml | 2 +- benches/bench.rs | 4 ++-- src/lib.rs | 46 ++++++++++++++++++++++++++++++++-------------- src/main.rs | 9 +++++++-- 5 files changed, 43 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 913f89a..6fb7915 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -282,7 +282,7 @@ dependencies = [ [[package]] name = "jsonformat" -version = "0.1.0" +version = "1.0.0" dependencies = [ "clap 3.0.0-beta.2", "criterion", diff --git a/Cargo.toml b/Cargo.toml index dd5b306..fbc3d87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jsonformat" -version = "0.1.0" +version = "1.0.0" authors = ["Nilstrieb "] edition = "2018" license = "MIT" diff --git a/benches/bench.rs b/benches/bench.rs index 5bd3956..002aa06 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,10 +1,10 @@ use criterion::{criterion_group, criterion_main, Criterion}; -use jsonformat::format_json; +use jsonformat::{format_json, Indentation}; use std::{fs, io}; /// You need a json file called massive.json in your project root fn format_massive_json(file: &str) -> io::Result { - Ok(format_json(&file, None)) + Ok(format_json(&file, Indentation::Default)) } fn criterion_benchmark(c: &mut Criterion) { diff --git a/src/lib.rs b/src/lib.rs index 22e4aab..13f0612 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,31 @@ +//! +//! jsonformat is a library for formatting json. +//! +//! It does not do anything more than that, which makes it so fast. + +/// +/// Set the indentation used for the formatting. +/// +/// Note: It is *not* recommended to set indentation to anything oder than some spaces or some tabs, +/// but nothing is stopping you from doing that. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum Indentation<'a> { + /// Use the default indentation, which is two spaces + Default, + /// Use a custom indentation String + Custom(&'a str), +} + /// /// # Formats a json string /// -/// The indentation can be set to any custom value +/// The indentation can be set to any value using [Indentation](jsonformat::Indentation) /// The default value is two spaces /// The default indentation is faster than a custom one /// -pub fn format_json(json: &str, indentation: Option<&str>) -> String { +pub fn format_json(json: &str, indentation: Indentation) -> String { // at least as big as the input to avoid resizing - // this might be too big if the input string is formatted in a weird way, but that's not expected + // this might be too big if the input string is formatted in a weird way, but that's not expected, and it will still be efficient let mut out = String::with_capacity(json.len()); let mut escaped = false; @@ -86,14 +104,14 @@ pub fn format_json(json: &str, indentation: Option<&str>) -> String { out } -fn indent(buf: &mut String, level: usize, indent_str: Option<&str>) { +fn indent(buf: &mut String, level: usize, indent_str: Indentation) { for _ in 0..level { match indent_str { - None => { + Indentation::Default => { buf.push(' '); buf.push(' '); } - Some(indent) => { + Indentation::Custom(indent) => { buf.push_str(indent); } } @@ -107,27 +125,27 @@ mod test { #[test] fn echoes_primitive() { let json = "1.35"; - assert_eq!(json, format_json(json, None)); + assert_eq!(json, format_json(json, Indentation::Default)); } #[test] fn ignore_whitespace_in_string() { let json = "\" hallo \""; - assert_eq!(json, format_json(json, None)); + assert_eq!(json, format_json(json, Indentation::Default)); } #[test] fn remove_leading_whitespace() { let json = " 0"; let expected = "0"; - assert_eq!(expected, format_json(json, None)); + assert_eq!(expected, format_json(json, Indentation::Default)); } #[test] fn handle_escaped_strings() { let json = " \" hallo \\\" \" "; let expected = "\" hallo \\\" \""; - assert_eq!(expected, format_json(json, None)); + assert_eq!(expected, format_json(json, Indentation::Default)); } #[test] @@ -136,7 +154,7 @@ mod test { let expected = "{ \"a\": 0 }"; - assert_eq!(expected, format_json(json, None)); + assert_eq!(expected, format_json(json, Indentation::Default)); } #[test] @@ -147,7 +165,7 @@ mod test { 2, null ]"; - assert_eq!(expected, format_json(json, None)); + assert_eq!(expected, format_json(json, Indentation::Default)); } #[test] @@ -163,7 +181,7 @@ mod test { } ]"; - assert_eq!(expected, format_json(json, None)); + assert_eq!(expected, format_json(json, Indentation::Default)); } #[test] @@ -178,6 +196,6 @@ mod test { } ]"; - assert_eq!(expected, format_json(expected, None)); + assert_eq!(expected, format_json(expected, Indentation::Default)); } } diff --git a/src/main.rs b/src/main.rs index 501a4c7..238950f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ use clap::clap_app; -use jsonformat::format_json; +use jsonformat::{format_json, Indentation}; use std::fs; use std::io; use std::io::Read; @@ -36,7 +36,12 @@ fn main() -> Result<(), io::Error> { .replace("t", "\t") }); - let formatted = format_json(&str, replaced_indent.as_deref()); + let indent = match replaced_indent { + Some(ref str) => Indentation::Custom(str), + None => Indentation::Default, + }; + + let formatted = format_json(&str, indent); let mut output = matches.value_of("output"); let mut windows_output_default_file: Option = None; From e494ce933e0cdf6d8f71a9b7aebe1f79c5e9a9fb Mon Sep 17 00:00:00 2001 From: Nilstrieb Date: Wed, 18 Aug 2021 19:24:12 +0200 Subject: [PATCH 09/28] clap hotfix --- Cargo.lock | 136 +++++++---------------------------------------------- Cargo.toml | 4 +- 2 files changed, 18 insertions(+), 122 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6fb7915..d728d15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,14 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + [[package]] name = "atty" version = "0.2.14" @@ -62,43 +71,15 @@ version = "2.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ - "bitflags", - "textwrap 0.11.0", - "unicode-width", -] - -[[package]] -name = "clap" -version = "3.0.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd1061998a501ee7d4b6d449020df3266ca3124b941ec56cf2005c3779ca142" -dependencies = [ + "ansi_term", "atty", "bitflags", - "clap_derive", - "indexmap", - "lazy_static", - "os_str_bytes", "strsim", - "termcolor", - "textwrap 0.12.1", + "textwrap", "unicode-width", "vec_map", ] -[[package]] -name = "clap_derive" -version = "3.0.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "370f715b81112975b1b69db93e0b56ea4cd4e5002ac43b2da8474106a54096a1" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "criterion" version = "0.3.4" @@ -107,7 +88,7 @@ checksum = "ab327ed7354547cc2ef43cbe20ef68b988e70b4b593cbd66a2a61733123a3d23" dependencies = [ "atty", "cast", - "clap 2.33.3", + "clap", "criterion-plot", "csv", "itertools 0.10.1", @@ -213,21 +194,6 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "hermit-abi" version = "0.1.19" @@ -237,16 +203,6 @@ dependencies = [ "libc", ] -[[package]] -name = "indexmap" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" -dependencies = [ - "autocfg", - "hashbrown", -] - [[package]] name = "itertools" version = "0.9.0" @@ -282,9 +238,9 @@ dependencies = [ [[package]] name = "jsonformat" -version = "1.0.0" +version = "1.0.1" dependencies = [ - "clap 3.0.0-beta.2", + "clap", "criterion", ] @@ -349,12 +305,6 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" -[[package]] -name = "os_str_bytes" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85" - [[package]] name = "plotters" version = "0.3.1" @@ -383,30 +333,6 @@ dependencies = [ "plotters-backend", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" version = "1.0.27" @@ -547,9 +473,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.10.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "syn" @@ -562,15 +488,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "termcolor" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" -dependencies = [ - "winapi-util", -] - [[package]] name = "textwrap" version = "0.11.0" @@ -580,15 +497,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "textwrap" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789" -dependencies = [ - "unicode-width", -] - [[package]] name = "tinytemplate" version = "1.2.1" @@ -599,12 +507,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "unicode-segmentation" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" - [[package]] name = "unicode-width" version = "0.1.8" @@ -623,12 +525,6 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" -[[package]] -name = "version_check" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" - [[package]] name = "walkdir" version = "2.3.2" diff --git a/Cargo.toml b/Cargo.toml index fbc3d87..9247338 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jsonformat" -version = "1.0.0" +version = "1.0.1" authors = ["Nilstrieb "] edition = "2018" license = "MIT" @@ -14,7 +14,7 @@ categories = ["command-line-utilities"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = { version= "3.0.0-beta.2", optional = true } +clap = { version= "2.33.3", optional = true } [dev-dependencies] criterion = "0.3" From e1653da51b25201839742bce974d6fba32c5e69a Mon Sep 17 00:00:00 2001 From: nils <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 18 Aug 2021 22:23:08 +0200 Subject: [PATCH 10/28] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6782992..b796609 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,8 @@ It formats over 60MB of nested JSON in under 0.4s. ## Install -Currently, you have to build and install it yourself. -`cargo build --release` -The executable can then be found in `target/release/jsonformat` +You need Rust installed on your system +`cargo install jsonformat` ## Usage ``` From 2dc937bba86755ce2aee05306ac3144198ee3cba Mon Sep 17 00:00:00 2001 From: Nicolas Musset Date: Thu, 19 Aug 2021 13:39:25 +0900 Subject: [PATCH 11/28] Refactor using a buffer for reading and a buffer for writing --- Cargo.lock | 18 +++++++++++++++++ Cargo.toml | 1 + src/lib.rs | 58 +++++++++++++++++++++++++++++++++++++---------------- src/main.rs | 36 +++++++++++++++++---------------- 4 files changed, 79 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d728d15..6861b53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "ansi_term" version = "0.11.0" @@ -9,6 +11,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "atty" version = "0.2.14" @@ -242,6 +250,7 @@ version = "1.0.1" dependencies = [ "clap", "criterion", + "utf8-chars", ] [[package]] @@ -519,6 +528,15 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "utf8-chars" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1348d8face79d019be7cbc0198e36bf93e160ddbfaa7bb54c9592627b9ec841" +dependencies = [ + "arrayvec", +] + [[package]] name = "vec_map" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index 9247338..11408e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ categories = ["command-line-utilities"] [dependencies] clap = { version= "2.33.3", optional = true } +utf8-chars = "1.0.0" [dev-dependencies] criterion = "0.3" diff --git a/src/lib.rs b/src/lib.rs index 13f0612..9d9de6d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,10 @@ //! //! It does not do anything more than that, which makes it so fast. +use std::io::{BufReader, BufWriter, Write}; +use utf8_chars::BufReadCharsExt; +use std::error::Error; + /// /// Set the indentation used for the formatting. /// @@ -24,16 +28,32 @@ pub enum Indentation<'a> { /// The default indentation is faster than a custom one /// pub fn format_json(json: &str, indentation: Indentation) -> String { - // at least as big as the input to avoid resizing - // this might be too big if the input string is formatted in a weird way, but that's not expected, and it will still be efficient - let mut out = String::with_capacity(json.len()); + let mut reader = BufReader::new(json.as_bytes()); + let mut writer = BufWriter::new(Vec::new()); + + format_json_buffered(&mut reader, &mut writer, indentation).unwrap(); + String::from_utf8(writer.into_inner().unwrap()).unwrap() +} + +/// +/// # Formats a json string +/// +/// The indentation can be set to any value using [Indentation](jsonformat::Indentation) +/// The default value is two spaces +/// The default indentation is faster than a custom one +/// +pub fn format_json_buffered(reader: &mut BufReader, writer: &mut BufWriter, indentation: Indentation) -> Result<(), Box> +where + R: std::io::Read, + W: std::io::Write { let mut escaped = false; let mut in_string = false; let mut indent_level = 0usize; let mut newline_requested = false; // invalidated if next character is ] or } - for char in json.chars() { + for char in reader.chars() { + let char = char?; if in_string { let mut escape_here = false; match char { @@ -49,7 +69,7 @@ pub fn format_json(json: &str, indentation: Indentation) -> String { } _ => {} } - out.push(char); + writer.write_all(char.encode_utf8(&mut [0; 4]).as_bytes())?; escaped = escape_here; } else { let mut auto_push = true; @@ -71,14 +91,14 @@ pub fn format_json(json: &str, indentation: Indentation) -> String { indent_level = indent_level.saturating_sub(1); if !newline_requested { // see comment below about newline_requested - out.push('\n'); - indent(&mut out, indent_level, indentation); + writeln!(writer)?; + indent_buffered(writer, indent_level, indentation)?; } } ':' => { auto_push = false; - out.push(char); - out.push(' '); + writer.write_all(char.encode_utf8(&mut [0; 4]).as_bytes())?; + writer.write_all(" ".as_bytes())?; } ',' => { request_newline = true; @@ -89,33 +109,37 @@ pub fn format_json(json: &str, indentation: Indentation) -> String { // newline only happens after { [ and , // this means we can safely assume that it being followed up by } or ] // means an empty object/array - out.push('\n'); - indent(&mut out, old_level, indentation); + writeln!(writer)?; + indent_buffered(writer, old_level, indentation)?; } if auto_push { - out.push(char); + writer.write_all(char.encode_utf8(&mut [0; 4]).as_bytes())?; } newline_requested = request_newline; } } - out + Ok(()) } -fn indent(buf: &mut String, level: usize, indent_str: Indentation) { +fn indent_buffered(writer: &mut BufWriter, level: usize, indent_str: Indentation) -> Result<(), Box> +where + W: std::io::Write { for _ in 0..level { match indent_str { Indentation::Default => { - buf.push(' '); - buf.push(' '); + writer.write_all(" ".as_bytes())?; + writer.write_all(" ".as_bytes())?; } Indentation::Custom(indent) => { - buf.push_str(indent); + writer.write_all(indent.as_bytes())?; } } } + + Ok(()) } #[cfg(test)] diff --git a/src/main.rs b/src/main.rs index 238950f..16ce1b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,10 @@ use clap::clap_app; -use jsonformat::{format_json, Indentation}; -use std::fs; -use std::io; -use std::io::Read; +use jsonformat::{Indentation, format_json_buffered}; +use std::error::Error; +use std::fs::File; +use std::io::{BufReader, BufWriter, Read, Write}; -fn main() -> Result<(), io::Error> { +fn main() -> Result<(), Box> { let matches = clap_app!(jsonformat => (version: "1.1") (author: "nilstrieb ") @@ -16,13 +16,13 @@ fn main() -> Result<(), io::Error> { ) .get_matches(); - let str = match matches.value_of("input") { - Some(path) => fs::read_to_string(path)?, + let reader: Box = match matches.value_of("input") { + Some(path) => { + let f = File::open(path)?; + Box::new(BufReader::new(f)) + }, None => { - let mut buf = String::new(); - let stdin = std::io::stdin(); - stdin.lock().read_to_string(&mut buf)?; - buf + Box::new(std::io::stdin()) } }; @@ -41,8 +41,6 @@ fn main() -> Result<(), io::Error> { None => Indentation::Default, }; - let formatted = format_json(&str, indent); - let mut output = matches.value_of("output"); let mut windows_output_default_file: Option = None; @@ -57,12 +55,16 @@ fn main() -> Result<(), io::Error> { output = windows_output_default_file.as_deref().or(output); - match output { + let writer : Box = match output { Some(file) => { - fs::write(file, formatted)?; + Box::new(File::create(file)?) } - None => println!("{}", formatted), - } + None => Box::new(std::io::stdout()), + }; + + let mut reader = BufReader::new(reader); + let mut writer = BufWriter::new(writer); + format_json_buffered(&mut reader, &mut writer, indent)?; Ok(()) } From 9e81e67551702e4ada41d3d0826d9f04eb3af38b Mon Sep 17 00:00:00 2001 From: Nicolas Musset Date: Sat, 21 Aug 2021 22:20:17 +0900 Subject: [PATCH 12/28] Format code with rustfmt --- src/lib.rs | 25 +++++++++++++++++-------- src/main.rs | 17 +++++------------ 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9d9de6d..b2a75a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,9 +3,9 @@ //! //! It does not do anything more than that, which makes it so fast. -use std::io::{BufReader, BufWriter, Write}; -use utf8_chars::BufReadCharsExt; use std::error::Error; +use std::io::{BufReader, BufWriter, Read, Write}; +use utf8_chars::BufReadCharsExt; /// /// Set the indentation used for the formatting. @@ -42,11 +42,15 @@ pub fn format_json(json: &str, indentation: Indentation) -> String { /// The default value is two spaces /// The default indentation is faster than a custom one /// -pub fn format_json_buffered(reader: &mut BufReader, writer: &mut BufWriter, indentation: Indentation) -> Result<(), Box> +pub fn format_json_buffered( + reader: &mut BufReader, + writer: &mut BufWriter, + indentation: Indentation, +) -> Result<(), Box> where - R: std::io::Read, - W: std::io::Write { - + R: Read, + W: Write, +{ let mut escaped = false; let mut in_string = false; let mut indent_level = 0usize; @@ -124,9 +128,14 @@ where Ok(()) } -fn indent_buffered(writer: &mut BufWriter, level: usize, indent_str: Indentation) -> Result<(), Box> +fn indent_buffered( + writer: &mut BufWriter, + level: usize, + indent_str: Indentation, +) -> Result<(), Box> where - W: std::io::Write { + W: std::io::Write, +{ for _ in 0..level { match indent_str { Indentation::Default => { diff --git a/src/main.rs b/src/main.rs index 16ce1b5..788f17c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ use clap::clap_app; -use jsonformat::{Indentation, format_json_buffered}; +use jsonformat::{format_json_buffered, Indentation}; use std::error::Error; use std::fs::File; use std::io::{BufReader, BufWriter, Read, Write}; @@ -17,13 +17,8 @@ fn main() -> Result<(), Box> { .get_matches(); let reader: Box = match matches.value_of("input") { - Some(path) => { - let f = File::open(path)?; - Box::new(BufReader::new(f)) - }, - None => { - Box::new(std::io::stdin()) - } + Some(path) => Box::new(File::open(path)?), + None => Box::new(std::io::stdin()), }; let replaced_indent = matches.value_of("indentation").map(|value| { @@ -55,10 +50,8 @@ fn main() -> Result<(), Box> { output = windows_output_default_file.as_deref().or(output); - let writer : Box = match output { - Some(file) => { - Box::new(File::create(file)?) - } + let writer: Box = match output { + Some(file) => Box::new(File::create(file)?), None => Box::new(std::io::stdout()), }; From 2a87a54b8a6122c819c3959569d8b4eec18a9f9a Mon Sep 17 00:00:00 2001 From: Nicolas Musset Date: Sun, 22 Aug 2021 10:55:24 +0900 Subject: [PATCH 13/28] No need to use crate utf8-chars, we can read/write at the byte level --- Cargo.lock | 16 ---------------- Cargo.toml | 1 - src/lib.rs | 38 ++++++++++++++++++-------------------- 3 files changed, 18 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6861b53..8c8ebea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,12 +11,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "atty" version = "0.2.14" @@ -250,7 +244,6 @@ version = "1.0.1" dependencies = [ "clap", "criterion", - "utf8-chars", ] [[package]] @@ -528,15 +521,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" -[[package]] -name = "utf8-chars" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1348d8face79d019be7cbc0198e36bf93e160ddbfaa7bb54c9592627b9ec841" -dependencies = [ - "arrayvec", -] - [[package]] name = "vec_map" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index 11408e8..9247338 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ categories = ["command-line-utilities"] [dependencies] clap = { version= "2.33.3", optional = true } -utf8-chars = "1.0.0" [dev-dependencies] criterion = "0.3" diff --git a/src/lib.rs b/src/lib.rs index b2a75a1..d30e9bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,6 @@ use std::error::Error; use std::io::{BufReader, BufWriter, Read, Write}; -use utf8_chars::BufReadCharsExt; /// /// Set the indentation used for the formatting. @@ -56,24 +55,24 @@ where let mut indent_level = 0usize; let mut newline_requested = false; // invalidated if next character is ] or } - for char in reader.chars() { + for char in reader.bytes() { let char = char?; if in_string { let mut escape_here = false; match char { - '"' => { + b'"' => { if !escaped { in_string = false; } } - '\\' => { + b'\\' => { if !escaped { escape_here = true; } } _ => {} } - writer.write_all(char.encode_utf8(&mut [0; 4]).as_bytes())?; + writer.write_all(&[char])?; escaped = escape_here; } else { let mut auto_push = true; @@ -81,44 +80,44 @@ where let old_level = indent_level; match char { - '"' => in_string = true, - ' ' | '\n' | '\t' => continue, - '[' => { + b'"' => in_string = true, + b' ' | b'\n' | b'\t' => continue, + b'[' => { indent_level += 1; request_newline = true; } - '{' => { + b'{' => { indent_level += 1; request_newline = true; } - '}' | ']' => { + b'}' | b']' => { indent_level = indent_level.saturating_sub(1); if !newline_requested { // see comment below about newline_requested - writeln!(writer)?; + writer.write_all(&[b'\n'])?; indent_buffered(writer, indent_level, indentation)?; } } - ':' => { + b':' => { auto_push = false; - writer.write_all(char.encode_utf8(&mut [0; 4]).as_bytes())?; - writer.write_all(" ".as_bytes())?; + writer.write_all(&[char])?; + writer.write_all(&[b' '])?; } - ',' => { + b',' => { request_newline = true; } _ => {} } - if newline_requested && char != ']' && char != '}' { + if newline_requested && char != b']' && char != b'}' { // newline only happens after { [ and , // this means we can safely assume that it being followed up by } or ] // means an empty object/array - writeln!(writer)?; + writer.write_all(&[b'\n'])?; indent_buffered(writer, old_level, indentation)?; } if auto_push { - writer.write_all(char.encode_utf8(&mut [0; 4]).as_bytes())?; + writer.write_all(&[char])?; } newline_requested = request_newline; @@ -139,8 +138,7 @@ where for _ in 0..level { match indent_str { Indentation::Default => { - writer.write_all(" ".as_bytes())?; - writer.write_all(" ".as_bytes())?; + writer.write_all(b" ")?; } Indentation::Custom(indent) => { writer.write_all(indent.as_bytes())?; From 0d24310cbf8c7c82412d180faaa9a3e80d39f424 Mon Sep 17 00:00:00 2001 From: Nicolas Musset Date: Mon, 23 Aug 2021 14:56:57 +0900 Subject: [PATCH 14/28] On-stack dynamic dispatch to avoid boxing --- src/main.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index 788f17c..778395c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,9 +16,17 @@ fn main() -> Result<(), Box> { ) .get_matches(); - let reader: Box = match matches.value_of("input") { - Some(path) => Box::new(File::open(path)?), - None => Box::new(std::io::stdin()), + // Note: on-stack dynamic dispatch + let (mut file, mut stdin); + let reader: &mut dyn Read = match matches.value_of("input") { + Some(path) => { + file = File::open(path)?; + &mut file + } + None => { + stdin = std::io::stdin(); + &mut stdin + } }; let replaced_indent = matches.value_of("indentation").map(|value| { @@ -50,9 +58,17 @@ fn main() -> Result<(), Box> { output = windows_output_default_file.as_deref().or(output); - let writer: Box = match output { - Some(file) => Box::new(File::create(file)?), - None => Box::new(std::io::stdout()), + // Note: on-stack dynamic dispatch + let (mut file, mut stdout); + let writer: &mut dyn Write = match output { + Some(filename) => { + file = File::create(filename)?; + &mut file + }, + None => { + stdout = std::io::stdout(); + &mut stdout + }, }; let mut reader = BufReader::new(reader); From 724def5467d4115b92e5eb92247767381d0587d7 Mon Sep 17 00:00:00 2001 From: nils <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 4 Sep 2021 17:15:42 +0200 Subject: [PATCH 15/28] Update Cargo.toml --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9247338..2575375 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jsonformat" -version = "1.0.1" +version = "1.2.0" authors = ["Nilstrieb "] edition = "2018" license = "MIT" @@ -34,4 +34,4 @@ required-features = ["bin"] [[bench]] name = "bench" -harness = false \ No newline at end of file +harness = false From d3d9bb8a0076f84bba1dc9a1cea445163a992a6f Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Thu, 28 Apr 2022 19:56:10 +0200 Subject: [PATCH 16/28] make separate binary crate --- Cargo.lock | 176 ++++++++++++++-------------- Cargo.toml | 33 ++---- jsonformat-cli/Cargo.toml | 23 ++++ {src => jsonformat-cli/src}/main.rs | 0 4 files changed, 122 insertions(+), 110 deletions(-) create mode 100644 jsonformat-cli/Cargo.toml rename {src => jsonformat-cli/src}/main.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 8c8ebea..133d832 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bitflags" @@ -36,9 +36,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "bstr" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ "lazy_static", "memchr", @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.7.0" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" [[package]] name = "cast" @@ -84,16 +84,16 @@ dependencies = [ [[package]] name = "criterion" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab327ed7354547cc2ef43cbe20ef68b988e70b4b593cbd66a2a61733123a3d23" +checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" dependencies = [ "atty", "cast", "clap", "criterion-plot", "csv", - "itertools 0.10.1", + "itertools", "lazy_static", "num-traits", "oorandom", @@ -110,19 +110,19 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d" +checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57" dependencies = [ "cast", - "itertools 0.9.0", + "itertools", ] [[package]] name = "crossbeam-channel" -version = "0.5.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" dependencies = [ "cfg-if", "crossbeam-utils", @@ -130,9 +130,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -141,10 +141,11 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.5" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" dependencies = [ + "autocfg", "cfg-if", "crossbeam-utils", "lazy_static", @@ -154,9 +155,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ "cfg-if", "lazy_static", @@ -170,7 +171,7 @@ checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" dependencies = [ "bstr", "csv-core", - "itoa", + "itoa 0.4.8", "ryu", "serde", ] @@ -192,9 +193,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "half" -version = "1.7.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "hermit-abi" @@ -207,43 +208,47 @@ dependencies = [ [[package]] name = "itertools" -version = "0.9.0" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" dependencies = [ "either", ] [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "js-sys" -version = "0.3.51" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" dependencies = [ "wasm-bindgen", ] [[package]] name = "jsonformat" -version = "1.0.1" +version = "1.2.0" +dependencies = [ + "criterion", +] + +[[package]] +name = "jsonformat-cli" +version = "0.1.0" dependencies = [ "clap", - "criterion", + "jsonformat", ] [[package]] @@ -260,24 +265,24 @@ checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" [[package]] name = "log" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" dependencies = [ "cfg-if", ] [[package]] name = "memchr" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "memoffset" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ "autocfg", ] @@ -293,9 +298,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", "libc", @@ -337,27 +342,27 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.27" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] [[package]] name = "rayon" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +checksum = "fd249e82c21598a9a426a4e00dd7adc1d640b22445ec8545feef801d1a74c221" dependencies = [ "autocfg", "crossbeam-deque", @@ -367,22 +372,21 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +checksum = "9f51245e1e62e1f1629cbfec37b5793bbabcaeb90f30e94d2ba03564687353e4" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "lazy_static", "num_cpus", ] [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "regex-syntax", ] @@ -410,9 +414,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "same-file" @@ -431,21 +435,21 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "semver" -version = "1.0.3" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f3aac57ee7f3272d8395c6e4f502f434f0e289fcd62876f70daa008c20dcabe" +checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4" [[package]] name = "serde" -version = "1.0.126" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" [[package]] name = "serde_cbor" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" dependencies = [ "half", "serde", @@ -453,9 +457,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.126" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" dependencies = [ "proc-macro2", "quote", @@ -464,11 +468,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" dependencies = [ - "itoa", + "itoa 1.0.1", "ryu", "serde", ] @@ -481,9 +485,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "syn" -version = "1.0.73" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" +checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" dependencies = [ "proc-macro2", "quote", @@ -540,9 +544,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.74" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -550,9 +554,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.74" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" dependencies = [ "bumpalo", "lazy_static", @@ -565,9 +569,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.74" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -575,9 +579,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.74" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" dependencies = [ "proc-macro2", "quote", @@ -588,15 +592,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.74" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" [[package]] name = "web-sys" -version = "0.3.51" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582" +checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 2575375..eebf406 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,37 +1,22 @@ +[workspace] +members = [".", "jsonformat-cli"] + [package] name = "jsonformat" version = "1.2.0" authors = ["Nilstrieb "] -edition = "2018" +edition = "2021" license = "MIT" description = "Formats JSON extremely fast" homepage = "https://github.com/Nilstrieb/jsonformat" repository = "https://github.com/Nilstrieb/jsonformat" readme = "README.md" -keywords = ["json", "formatting", "cli"] -categories = ["command-line-utilities"] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -clap = { version= "2.33.3", optional = true } - -[dev-dependencies] -criterion = "0.3" - -[features] -default = ["bin"] -bin = ["clap"] - -[lib] -name = "jsonformat" -path = "src/lib.rs" - -[[bin]] -name = "jsonformat" -path = "src/main.rs" -required-features = ["bin"] +keywords = ["json", "formatting"] +categories = ["parser-implementations"] [[bench]] name = "bench" harness = false + +[dev-dependencies] +criterion = "0.3.5" diff --git a/jsonformat-cli/Cargo.toml b/jsonformat-cli/Cargo.toml new file mode 100644 index 0000000..7bc4a52 --- /dev/null +++ b/jsonformat-cli/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "jsonformat-cli" +version = "0.1.0" +authors = ["Nilstrieb "] +edition = "2021" +license = "MIT" +description = "Formats JSON extremely fast" +homepage = "https://github.com/Nilstrieb/jsonformat" +repository = "https://github.com/Nilstrieb/jsonformat" +readme = "README.md" +keywords = ["json", "formatting", "cli"] +categories = ["command-line-utilities"] + + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +jsonformat = { path = "..", version = "1.2.0" } +clap = "2.33.3" + +[[bin]] +name = "jsonformat" +path = "src/main.rs" \ No newline at end of file diff --git a/src/main.rs b/jsonformat-cli/src/main.rs similarity index 100% rename from src/main.rs rename to jsonformat-cli/src/main.rs From 6ba29e54e08328b9dc3220d580d0558e9e82bc01 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Thu, 28 Apr 2022 20:35:33 +0200 Subject: [PATCH 17/28] cleanup --- .gitignore | 6 ---- .rustfmt.toml | 3 ++ Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 17 ++++++----- benches/bench.rs | 33 +++++++++++++++------ jsonformat-cli/Cargo.toml | 2 +- jsonformat-cli/src/main.rs | 17 ++++++----- src/lib.rs | 61 +++++++++++++++++--------------------- 9 files changed, 77 insertions(+), 66 deletions(-) create mode 100644 .rustfmt.toml diff --git a/.gitignore b/.gitignore index 0049502..89c0fff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,3 @@ /target .idea *.iml - -# test data -*.json - -# local install script -install.sh \ No newline at end of file diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..4d7dd9e --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,3 @@ +imports_granularity = "Crate" +newline_style = "Unix" +group_imports = "StdExternalCrate" \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 133d832..bdbdcaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -238,7 +238,7 @@ dependencies = [ [[package]] name = "jsonformat" -version = "1.2.0" +version = "2.0.0" dependencies = [ "criterion", ] diff --git a/Cargo.toml b/Cargo.toml index eebf406..24e0626 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = [".", "jsonformat-cli"] [package] name = "jsonformat" -version = "1.2.0" +version = "2.0.0" authors = ["Nilstrieb "] edition = "2021" license = "MIT" diff --git a/README.md b/README.md index b796609..b42e9f8 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,13 @@ `jsonformat` is an extremely fast JSON formatter. -It formats over 60MB of nested JSON in under 0.4s. +It formats over 20MB of nested JSON in 60ms. + +For the library, look at [docs.rs](https://docs.rs/jsonformat) ## Install You need Rust installed on your system -`cargo install jsonformat` +`cargo install jsonformat-cli` ## Usage ``` @@ -28,13 +30,14 @@ OPTIONS: Reads from stdin if no file is supplied. Outputs to stdout if no output file is specified. -On windows, it writes to a file called `_f.json`, unless the `--stdout` flag is used or a custom output file is provided. This it to enable drag-and-drop in windows explorer. +On Windows, it writes to a file called `_f.json`, unless the `--stdout` flag is used or a custom output +file is provided. This it to enable drag-and-drop in Windows explorer. ## Error handling -`jsonformat` does not report malformed json - it can't even fully know whether the json is actually malformed. Malformed json is just formatted kind of incorrectly, with no data lost and no crashes. If you find one, open an issue, +`jsonformat` does not report malformed json - it can't even fully know whether the json is actually malformed. +Malformed json is just formatted kind of incorrectly, with no data lost and no crashes. If you find one, open an issue, ## How? -`jsonformat` does not actually parse the json, it just loops through each character and keeps track of some flags. It then copies these characters to the output buffer, adding and removing whitespace. - -The code is currently a bit chaotic, but it works and is fast, so good enough for now. Maybe it could profit from SIMD in the future, but I have never used it and I don't know whether it would work. Maybe some day... +`jsonformat` does not actually parse the json, it just loops through each character and keeps track of some flags. +It then copies these characters to the output buffer, adding and removing whitespace. diff --git a/benches/bench.rs b/benches/bench.rs index 002aa06..e4fa293 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,17 +1,32 @@ -use criterion::{criterion_group, criterion_main, Criterion}; -use jsonformat::{format_json, Indentation}; use std::{fs, io}; -/// You need a json file called massive.json in your project root -fn format_massive_json(file: &str) -> io::Result { - Ok(format_json(&file, Indentation::Default)) -} +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use jsonformat::{format, format_reader_writer, Indentation}; fn criterion_benchmark(c: &mut Criterion) { - let file = fs::read_to_string("massive.json").expect("massive.json file in project directory"); + let file = include_str!("large-file.json"); - c.bench_function("Format massive json", |b| { - b.iter(|| format_massive_json(&file)) + c.bench_function("Format json default settings", |b| { + b.iter(|| { + let json = format(&file, Indentation::Default); + black_box(json); + }) + }); + + c.bench_function("Format json custom indentation", |b| { + b.iter(|| { + let json = format(&file, Indentation::Custom("123456")); + black_box(json); + }) + }); + + c.bench_function("Format json no utf8 validation", |b| { + b.iter(|| { + let mut writer = Vec::with_capacity(file.len() * 2); + + format_reader_writer(file.as_bytes(), &mut writer, Indentation::Default).unwrap(); + black_box(writer); + }) }); } diff --git a/jsonformat-cli/Cargo.toml b/jsonformat-cli/Cargo.toml index 7bc4a52..9e49162 100644 --- a/jsonformat-cli/Cargo.toml +++ b/jsonformat-cli/Cargo.toml @@ -15,7 +15,7 @@ categories = ["command-line-utilities"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -jsonformat = { path = "..", version = "1.2.0" } +jsonformat = { path = "..", version = "2.0.0" } clap = "2.33.3" [[bin]] diff --git a/jsonformat-cli/src/main.rs b/jsonformat-cli/src/main.rs index 778395c..8834d86 100644 --- a/jsonformat-cli/src/main.rs +++ b/jsonformat-cli/src/main.rs @@ -1,8 +1,11 @@ +use std::{ + error::Error, + fs::File, + io::{BufReader, BufWriter, Read, Write}, +}; + use clap::clap_app; -use jsonformat::{format_json_buffered, Indentation}; -use std::error::Error; -use std::fs::File; -use std::io::{BufReader, BufWriter, Read, Write}; +use jsonformat::{format_reader_writer, Indentation}; fn main() -> Result<(), Box> { let matches = clap_app!(jsonformat => @@ -64,16 +67,16 @@ fn main() -> Result<(), Box> { Some(filename) => { file = File::create(filename)?; &mut file - }, + } None => { stdout = std::io::stdout(); &mut stdout - }, + } }; let mut reader = BufReader::new(reader); let mut writer = BufWriter::new(writer); - format_json_buffered(&mut reader, &mut writer, indent)?; + format_reader_writer(&mut reader, &mut writer, indent)?; Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index d30e9bc..e3d67a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,10 +3,11 @@ //! //! It does not do anything more than that, which makes it so fast. -use std::error::Error; -use std::io::{BufReader, BufWriter, Read, Write}; +use std::{ + io, + io::{Read, Write}, +}; -/// /// Set the indentation used for the formatting. /// /// Note: It is *not* recommended to set indentation to anything oder than some spaces or some tabs, @@ -19,33 +20,29 @@ pub enum Indentation<'a> { Custom(&'a str), } -/// /// # Formats a json string /// -/// The indentation can be set to any value using [Indentation](jsonformat::Indentation) +/// The indentation can be set to any value using [`Indentation`] /// The default value is two spaces /// The default indentation is faster than a custom one -/// -pub fn format_json(json: &str, indentation: Indentation) -> String { - let mut reader = BufReader::new(json.as_bytes()); - let mut writer = BufWriter::new(Vec::new()); +pub fn format(json: &str, indentation: Indentation) -> String { + let mut reader = json.as_bytes(); + let mut writer = Vec::with_capacity(json.len()); - format_json_buffered(&mut reader, &mut writer, indentation).unwrap(); - String::from_utf8(writer.into_inner().unwrap()).unwrap() + format_reader_writer(&mut reader, &mut writer, indentation).unwrap(); + String::from_utf8(writer).unwrap() } -/// /// # Formats a json string /// -/// The indentation can be set to any value using [Indentation](jsonformat::Indentation) +/// The indentation can be set to any value using [`Indentation`] /// The default value is two spaces /// The default indentation is faster than a custom one -/// -pub fn format_json_buffered( - reader: &mut BufReader, - writer: &mut BufWriter, +pub fn format_reader_writer( + reader: R, + mut writer: W, indentation: Indentation, -) -> Result<(), Box> +) -> io::Result<()> where R: Read, W: Write, @@ -95,7 +92,7 @@ where if !newline_requested { // see comment below about newline_requested writer.write_all(&[b'\n'])?; - indent_buffered(writer, indent_level, indentation)?; + indent(&mut writer, indent_level, indentation)?; } } b':' => { @@ -113,7 +110,7 @@ where // this means we can safely assume that it being followed up by } or ] // means an empty object/array writer.write_all(&[b'\n'])?; - indent_buffered(writer, old_level, indentation)?; + indent(&mut writer, old_level, indentation)?; } if auto_push { @@ -127,13 +124,9 @@ where Ok(()) } -fn indent_buffered( - writer: &mut BufWriter, - level: usize, - indent_str: Indentation, -) -> Result<(), Box> +fn indent(writer: &mut W, level: usize, indent_str: Indentation) -> io::Result<()> where - W: std::io::Write, + W: Write, { for _ in 0..level { match indent_str { @@ -156,27 +149,27 @@ mod test { #[test] fn echoes_primitive() { let json = "1.35"; - assert_eq!(json, format_json(json, Indentation::Default)); + assert_eq!(json, format(json, Indentation::Default)); } #[test] fn ignore_whitespace_in_string() { let json = "\" hallo \""; - assert_eq!(json, format_json(json, Indentation::Default)); + assert_eq!(json, format(json, Indentation::Default)); } #[test] fn remove_leading_whitespace() { let json = " 0"; let expected = "0"; - assert_eq!(expected, format_json(json, Indentation::Default)); + assert_eq!(expected, format(json, Indentation::Default)); } #[test] fn handle_escaped_strings() { let json = " \" hallo \\\" \" "; let expected = "\" hallo \\\" \""; - assert_eq!(expected, format_json(json, Indentation::Default)); + assert_eq!(expected, format(json, Indentation::Default)); } #[test] @@ -185,7 +178,7 @@ mod test { let expected = "{ \"a\": 0 }"; - assert_eq!(expected, format_json(json, Indentation::Default)); + assert_eq!(expected, format(json, Indentation::Default)); } #[test] @@ -196,7 +189,7 @@ mod test { 2, null ]"; - assert_eq!(expected, format_json(json, Indentation::Default)); + assert_eq!(expected, format(json, Indentation::Default)); } #[test] @@ -212,7 +205,7 @@ mod test { } ]"; - assert_eq!(expected, format_json(json, Indentation::Default)); + assert_eq!(expected, format(json, Indentation::Default)); } #[test] @@ -227,6 +220,6 @@ mod test { } ]"; - assert_eq!(expected, format_json(expected, Indentation::Default)); + assert_eq!(expected, format(expected, Indentation::Default)); } } From 32f901406b0bf57287d17f17c9d874867dcc0fcf Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Thu, 28 Apr 2022 20:51:56 +0200 Subject: [PATCH 18/28] binary cleanup --- Cargo.lock | 134 ++++++++++++++++++++++++++++++++----- jsonformat-cli/Cargo.toml | 5 +- jsonformat-cli/src/main.rs | 80 +++++++++++----------- 3 files changed, 158 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bdbdcaa..43befae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,13 +3,10 @@ version = 3 [[package]] -name = "ansi_term" -version = "0.11.0" +name = "anyhow" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -dependencies = [ - "winapi", -] +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" [[package]] name = "atty" @@ -73,13 +70,48 @@ version = "2.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ - "ansi_term", + "bitflags", + "textwrap 0.11.0", + "unicode-width", +] + +[[package]] +name = "clap" +version = "3.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c167e37342afc5f33fd87bbc870cedd020d2a6dffa05d45ccd9241fbdd146db" +dependencies = [ "atty", "bitflags", + "clap_derive", + "clap_lex", + "indexmap", + "lazy_static", "strsim", - "textwrap", - "unicode-width", - "vec_map", + "termcolor", + "textwrap 0.15.0", +] + +[[package]] +name = "clap_derive" +version = "3.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "189ddd3b5d32a70b35e7686054371742a937b0d99128e76dde6340210e966669" +dependencies = [ + "os_str_bytes", ] [[package]] @@ -90,7 +122,7 @@ checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" dependencies = [ "atty", "cast", - "clap", + "clap 2.33.3", "criterion-plot", "csv", "itertools", @@ -197,6 +229,18 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -206,6 +250,16 @@ dependencies = [ "libc", ] +[[package]] +name = "indexmap" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +dependencies = [ + "autocfg", + "hashbrown", +] + [[package]] name = "itertools" version = "0.10.3" @@ -247,7 +301,8 @@ dependencies = [ name = "jsonformat-cli" version = "0.1.0" dependencies = [ - "clap", + "anyhow", + "clap 3.1.12", "jsonformat", ] @@ -312,6 +367,12 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "os_str_bytes" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" + [[package]] name = "plotters" version = "0.3.1" @@ -340,6 +401,30 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.37" @@ -479,9 +564,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" @@ -494,6 +579,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -503,6 +597,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "textwrap" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" + [[package]] name = "tinytemplate" version = "1.2.1" @@ -526,10 +626,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] -name = "vec_map" -version = "0.8.2" +name = "version_check" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" diff --git a/jsonformat-cli/Cargo.toml b/jsonformat-cli/Cargo.toml index 9e49162..47a4a11 100644 --- a/jsonformat-cli/Cargo.toml +++ b/jsonformat-cli/Cargo.toml @@ -16,8 +16,9 @@ categories = ["command-line-utilities"] [dependencies] jsonformat = { path = "..", version = "2.0.0" } -clap = "2.33.3" +clap = { version = "3.1.12", features = ["derive"] } +anyhow = "1.0.57" [[bin]] name = "jsonformat" -path = "src/main.rs" \ No newline at end of file +path = "src/main.rs" diff --git a/jsonformat-cli/src/main.rs b/jsonformat-cli/src/main.rs index 8834d86..1d81709 100644 --- a/jsonformat-cli/src/main.rs +++ b/jsonformat-cli/src/main.rs @@ -1,45 +1,52 @@ use std::{ - error::Error, fs::File, + io, io::{BufReader, BufWriter, Read, Write}, + path::PathBuf, }; -use clap::clap_app; +use anyhow::Context; +use clap::Parser; use jsonformat::{format_reader_writer, Indentation}; -fn main() -> Result<(), Box> { - let matches = clap_app!(jsonformat => - (version: "1.1") - (author: "nilstrieb ") - (about: "Formats json from stdin or from a file") - (@arg stdout: -s --stdout "Output the result to stdout instead of the default output file. Windows only.") - (@arg indentation: -i --indent +takes_value "Set the indentation used (\\s for space, \\t for tab)") - (@arg output: -o --output +takes_value "The output file for the formatted json") - (@arg input: "The input file to format") - ) - .get_matches(); +#[derive(Parser)] +#[clap(author, about, version)] +struct Options { + #[clap(short, long)] + indentation: Option, + #[clap(short, long)] + output: Option, + input: Option, +} + +fn main() -> anyhow::Result<()> { + let options = Options::parse(); // Note: on-stack dynamic dispatch - let (mut file, mut stdin); - let reader: &mut dyn Read = match matches.value_of("input") { + // ugly af but works + let (mut file, stdin, mut stdin_lock); + let reader: &mut dyn Read = match &options.input { Some(path) => { - file = File::open(path)?; + file = File::open(path) + .context(format!("Name: {}", path.display())) + .context("Open input file")?; &mut file } None => { - stdin = std::io::stdin(); - &mut stdin + stdin = io::stdin(); + stdin_lock = stdin.lock(); + &mut stdin_lock } }; - let replaced_indent = matches.value_of("indentation").map(|value| { + let replaced_indent = options.indentation.map(|value| { value .to_lowercase() .chars() .filter(|c| ['s', 't'].contains(c)) .collect::() - .replace("s", " ") - .replace("t", "\t") + .replace('s', " ") + .replace('t', "\t") }); let indent = match replaced_indent { @@ -47,36 +54,25 @@ fn main() -> Result<(), Box> { None => Indentation::Default, }; - let mut output = matches.value_of("output"); - let mut windows_output_default_file: Option = None; - - #[cfg(windows)] - if !matches.is_present("stdout") { - if let Some(file) = matches.value_of("input") { - // on windows, set the default output file if no stdout flag is provided - // this makes it work with drag and drop in windows explorer - windows_output_default_file = Some(file.replace(".json", "_f.json")) - } - } - - output = windows_output_default_file.as_deref().or(output); - // Note: on-stack dynamic dispatch - let (mut file, mut stdout); - let writer: &mut dyn Write = match output { - Some(filename) => { - file = File::create(filename)?; + let (mut file, stdout, mut stdout_lock); + let writer: &mut dyn Write = match &options.output { + Some(path) => { + file = File::create(path) + .context(path.display().to_string()) + .context("Open output file")?; &mut file } None => { - stdout = std::io::stdout(); - &mut stdout + stdout = io::stdout(); + stdout_lock = stdout.lock(); + &mut stdout_lock } }; let mut reader = BufReader::new(reader); let mut writer = BufWriter::new(writer); - format_reader_writer(&mut reader, &mut writer, indent)?; + format_reader_writer(&mut reader, &mut writer, indent).context("failed to read or write")?; Ok(()) } From c044602972365af1b4800d791f60f0c116c3e676 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Thu, 28 Apr 2022 21:09:50 +0200 Subject: [PATCH 19/28] binary cleanup --- CHANGELOG.md | 5 ++++ Cargo.lock | 2 +- README.md | 3 --- benches/bench.rs | 20 ++++++++++---- jsonformat-cli/Cargo.toml | 2 +- jsonformat-cli/src/main.rs | 5 +++- src/lib.rs | 53 ++++++++++++++++++++++++-------------- 7 files changed, 59 insertions(+), 31 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9585a00 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# 2.0.0 + +There are many changes, the two formatting functions have been renamed, `format_reader_writer` now takes +a `W` and `R` instead of `&mut BufReader`, it now always adds a trailing newline. There may be a few more +small changes. \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 43befae..30e9682 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -299,7 +299,7 @@ dependencies = [ [[package]] name = "jsonformat-cli" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anyhow", "clap 3.1.12", diff --git a/README.md b/README.md index b42e9f8..2c31bdd 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,6 @@ OPTIONS: Reads from stdin if no file is supplied. Outputs to stdout if no output file is specified. -On Windows, it writes to a file called `_f.json`, unless the `--stdout` flag is used or a custom output -file is provided. This it to enable drag-and-drop in Windows explorer. - ## Error handling `jsonformat` does not report malformed json - it can't even fully know whether the json is actually malformed. Malformed json is just formatted kind of incorrectly, with no data lost and no crashes. If you find one, open an issue, diff --git a/benches/bench.rs b/benches/bench.rs index e4fa293..e750acf 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,21 +1,26 @@ -use std::{fs, io}; +use std::{fs, io, path::PathBuf}; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use jsonformat::{format, format_reader_writer, Indentation}; fn criterion_benchmark(c: &mut Criterion) { - let file = include_str!("large-file.json"); + // using `include_str` makes the benches a lot less reliable for some reason??? + let file = PathBuf::from(file!()) + .parent() + .unwrap() + .join("large-file.json"); + let file = fs::read_to_string(file).unwrap(); c.bench_function("Format json default settings", |b| { b.iter(|| { - let json = format(&file, Indentation::Default); + let json = format(black_box(&file), Indentation::TwoSpace); black_box(json); }) }); c.bench_function("Format json custom indentation", |b| { b.iter(|| { - let json = format(&file, Indentation::Custom("123456")); + let json = format(black_box(&file), Indentation::Custom("123456")); black_box(json); }) }); @@ -24,7 +29,12 @@ fn criterion_benchmark(c: &mut Criterion) { b.iter(|| { let mut writer = Vec::with_capacity(file.len() * 2); - format_reader_writer(file.as_bytes(), &mut writer, Indentation::Default).unwrap(); + format_reader_writer( + black_box(file.as_bytes()), + &mut writer, + Indentation::TwoSpace, + ) + .unwrap(); black_box(writer); }) }); diff --git a/jsonformat-cli/Cargo.toml b/jsonformat-cli/Cargo.toml index 47a4a11..29de058 100644 --- a/jsonformat-cli/Cargo.toml +++ b/jsonformat-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jsonformat-cli" -version = "0.1.0" +version = "0.2.0" authors = ["Nilstrieb "] edition = "2021" license = "MIT" diff --git a/jsonformat-cli/src/main.rs b/jsonformat-cli/src/main.rs index 1d81709..305532e 100644 --- a/jsonformat-cli/src/main.rs +++ b/jsonformat-cli/src/main.rs @@ -12,10 +12,13 @@ use jsonformat::{format_reader_writer, Indentation}; #[derive(Parser)] #[clap(author, about, version)] struct Options { + /// The indentation, s will replaced by a space and t by a tab. ss is the default. #[clap(short, long)] indentation: Option, #[clap(short, long)] + /// The output file output: Option, + /// The input file input: Option, } @@ -51,7 +54,7 @@ fn main() -> anyhow::Result<()> { let indent = match replaced_indent { Some(ref str) => Indentation::Custom(str), - None => Indentation::Default, + None => Indentation::TwoSpace, }; // Note: on-stack dynamic dispatch diff --git a/src/lib.rs b/src/lib.rs index e3d67a2..12d83ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,11 +15,17 @@ use std::{ #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Indentation<'a> { /// Use the default indentation, which is two spaces - Default, + TwoSpace, /// Use a custom indentation String Custom(&'a str), } +impl Default for Indentation<'_> { + fn default() -> Self { + Self::TwoSpace + } +} + /// # Formats a json string /// /// The indentation can be set to any value using [`Indentation`] @@ -91,7 +97,7 @@ where indent_level = indent_level.saturating_sub(1); if !newline_requested { // see comment below about newline_requested - writer.write_all(&[b'\n'])?; + writer.write_all(b"\n")?; indent(&mut writer, indent_level, indentation)?; } } @@ -109,7 +115,7 @@ where // newline only happens after { [ and , // this means we can safely assume that it being followed up by } or ] // means an empty object/array - writer.write_all(&[b'\n'])?; + writer.write_all(b"\n")?; indent(&mut writer, old_level, indentation)?; } @@ -121,6 +127,9 @@ where } } + // trailing newline + writer.write_all(b"\n")?; + Ok(()) } @@ -130,7 +139,7 @@ where { for _ in 0..level { match indent_str { - Indentation::Default => { + Indentation::TwoSpace => { writer.write_all(b" ")?; } Indentation::Custom(indent) => { @@ -148,28 +157,28 @@ mod test { #[test] fn echoes_primitive() { - let json = "1.35"; - assert_eq!(json, format(json, Indentation::Default)); + let json = "1.35\n"; + assert_eq!(json, format(json, Indentation::TwoSpace)); } #[test] fn ignore_whitespace_in_string() { - let json = "\" hallo \""; - assert_eq!(json, format(json, Indentation::Default)); + let json = "\" hallo \"\n"; + assert_eq!(json, format(json, Indentation::TwoSpace)); } #[test] fn remove_leading_whitespace() { let json = " 0"; - let expected = "0"; - assert_eq!(expected, format(json, Indentation::Default)); + let expected = "0\n"; + assert_eq!(expected, format(json, Indentation::TwoSpace)); } #[test] fn handle_escaped_strings() { let json = " \" hallo \\\" \" "; - let expected = "\" hallo \\\" \""; - assert_eq!(expected, format(json, Indentation::Default)); + let expected = "\" hallo \\\" \"\n"; + assert_eq!(expected, format(json, Indentation::TwoSpace)); } #[test] @@ -177,8 +186,9 @@ mod test { let json = "{\"a\":0}"; let expected = "{ \"a\": 0 -}"; - assert_eq!(expected, format(json, Indentation::Default)); +} +"; + assert_eq!(expected, format(json, Indentation::TwoSpace)); } #[test] @@ -188,8 +198,9 @@ mod test { 1, 2, null -]"; - assert_eq!(expected, format(json, Indentation::Default)); +] +"; + assert_eq!(expected, format(json, Indentation::TwoSpace)); } #[test] @@ -203,9 +214,10 @@ mod test { { \"a\": null } -]"; +] +"; - assert_eq!(expected, format(json, Indentation::Default)); + assert_eq!(expected, format(json, Indentation::TwoSpace)); } #[test] @@ -218,8 +230,9 @@ mod test { { \"a\": null } -]"; +] +"; - assert_eq!(expected, format(expected, Indentation::Default)); + assert_eq!(expected, format(expected, Indentation::TwoSpace)); } } From 9ca41bf08b4ff942f2f2f4a41efc6c5b0c097171 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Thu, 28 Apr 2022 21:16:43 +0200 Subject: [PATCH 20/28] prepare for release --- CHANGELOG.md | 3 ++- README.md | 27 ++++++++++++++++----------- benches/bench.rs | 2 +- src/lib.rs | 12 +++++++++++- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9585a00..4fc3cf5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # 2.0.0 There are many changes, the two formatting functions have been renamed, `format_reader_writer` now takes -a `W` and `R` instead of `&mut BufReader`, it now always adds a trailing newline. There may be a few more +a `W` and `R` instead of `&mut BufReader`, it now always adds a trailing newline. `Indentation::Default` was +renamed to `Indentation::TwoSpaces` and `FourSpaces` and `Tab` were added. There may be a few more small changes. \ No newline at end of file diff --git a/README.md b/README.md index 2c31bdd..e8d9b77 100644 --- a/README.md +++ b/README.md @@ -4,27 +4,32 @@ It formats over 20MB of nested JSON in 60ms. -For the library, look at [docs.rs](https://docs.rs/jsonformat) +## Library crate -## Install +For the library crate, look at [docs.rs](https://docs.rs/jsonformat) + +## Binary Install You need Rust installed on your system `cargo install jsonformat-cli` -## Usage +## Binary Usage ``` +jsonformat-cli 0.2.0 +Nilstrieb +Formats JSON extremely fast + USAGE: - jsonformat [OPTIONS] [input] + jsonformat [OPTIONS] [INPUT] ARGS: - The input file to format - -FLAGS: - -h, --help Prints help information - -V, --version Prints version information + The input file OPTIONS: - -i, --indent Set the indentation used (\s for space, \t for tab) - -o, --output The output file for the formatted json + -h, --help Print help information + -i, --indentation The indentation, s will replaced by a space and t by a tab. + ss is the default + -o, --output The output file + -V, --version Print version information ``` Reads from stdin if no file is supplied. diff --git a/benches/bench.rs b/benches/bench.rs index e750acf..ac805cd 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,4 +1,4 @@ -use std::{fs, io, path::PathBuf}; +use std::{fs, path::PathBuf}; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use jsonformat::{format, format_reader_writer, Indentation}; diff --git a/src/lib.rs b/src/lib.rs index 12d83ef..172d68b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,8 +14,12 @@ use std::{ /// but nothing is stopping you from doing that. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Indentation<'a> { - /// Use the default indentation, which is two spaces + /// Fast path for two spaces TwoSpace, + /// Fast path for four spaces + FourSpace, + /// Fast path for tab + Tab, /// Use a custom indentation String Custom(&'a str), } @@ -142,6 +146,12 @@ where Indentation::TwoSpace => { writer.write_all(b" ")?; } + Indentation::FourSpace => { + writer.write_all(b" ")?; + } + Indentation::Tab => { + writer.write_all(b"\t")?; + } Indentation::Custom(indent) => { writer.write_all(indent.as_bytes())?; } From c38c322a483805194634b3fe5ca91972c6d506be Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Thu, 28 Apr 2022 21:19:17 +0200 Subject: [PATCH 21/28] prepare for release 2 --- Cargo.toml | 1 + jsonformat-cli/LICENSE | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 jsonformat-cli/LICENSE diff --git a/Cargo.toml b/Cargo.toml index 24e0626..22e9441 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ repository = "https://github.com/Nilstrieb/jsonformat" readme = "README.md" keywords = ["json", "formatting"] categories = ["parser-implementations"] +include = ["src/lib.rs", "Cargo.toml", "LICENSE", "README.md", "CHANGELOG.md"] [[bench]] name = "bench" diff --git a/jsonformat-cli/LICENSE b/jsonformat-cli/LICENSE new file mode 100644 index 0000000..f1754b8 --- /dev/null +++ b/jsonformat-cli/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 nilstrieb + +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. From afb7519746dabbd5503cc1d72f4846ced7764401 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Thu, 28 Apr 2022 21:21:45 +0200 Subject: [PATCH 22/28] add bench to include --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 22e9441..7f4dd05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ repository = "https://github.com/Nilstrieb/jsonformat" readme = "README.md" keywords = ["json", "formatting"] categories = ["parser-implementations"] -include = ["src/lib.rs", "Cargo.toml", "LICENSE", "README.md", "CHANGELOG.md"] +include = ["src/lib.rs", "Cargo.toml", "LICENSE", "README.md", "CHANGELOG.md", "benches/bench.rs"] [[bench]] name = "bench" From 5840f65ea0178a231fd73d1c7da9e80655519930 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Fri, 22 Sep 2023 22:00:45 +0200 Subject: [PATCH 23/28] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index e8d9b77..7f3bab0 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,6 @@ You need Rust installed on your system ## Binary Usage ``` jsonformat-cli 0.2.0 -Nilstrieb Formats JSON extremely fast USAGE: From ea61aa745a794a6f873659b3b3d713e199733901 Mon Sep 17 00:00:00 2001 From: Joel Depooter Date: Tue, 25 Feb 2025 11:30:59 -0800 Subject: [PATCH 24/28] Handle carriage returns in source JSON whitespace Previously any carriage return (\r) bytes in the JSON whitespace were not ignored. Instead they were included in the formatted output. This led to very bad formatting, as the indentation would include the carriage return. With this change, carriage returns are handled the same way that newlines are: they are ignored in the source JSON whitespace. It might be better to detect if the source JSON is using Windows (\r\n) newlines, and preserve that on the output. However, that is a much bigger change. For now I think it is sufficient to simply produce necely formatted output which uses only \n newlines. --- src/lib.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 172d68b..9362b99 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -88,7 +88,7 @@ where match char { b'"' => in_string = true, - b' ' | b'\n' | b'\t' => continue, + b' ' | b'\n' | b'\r' | b'\t' => continue, b'[' => { indent_level += 1; request_newline = true; @@ -245,4 +245,21 @@ mod test { assert_eq!(expected, format(expected, Indentation::TwoSpace)); } + + #[test] + fn contains_crlf() { + let json = "[\r\n{\r\n\"a\":0\r\n},\r\n{},\r\n{\r\n\"a\": null\r\n}\r\n]\r\n"; + let expected = "[ + { + \"a\": 0 + }, + {}, + { + \"a\": null + } +] +"; + + assert_eq!(expected, format(json, Indentation::TwoSpace)); + } } From 26b002451afaf29ad3f00f13070f3097914010b6 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Fri, 21 Mar 2025 18:20:49 +0100 Subject: [PATCH 25/28] update lockfile --- Cargo.lock | 484 ++++++++++++++++++++++++++++------------------------- 1 file changed, 258 insertions(+), 226 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 30e9682..f4c72e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,12 +1,21 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] [[package]] name = "anyhow" -version = "1.0.57" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" [[package]] name = "atty" @@ -21,42 +30,27 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", - "serde", -] +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" -version = "3.9.1" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cast" -version = "0.2.7" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" -dependencies = [ - "rustc_version", -] +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" @@ -66,9 +60,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "2.33.3" +version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "bitflags", "textwrap 0.11.0", @@ -77,52 +71,52 @@ dependencies = [ [[package]] name = "clap" -version = "3.1.12" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c167e37342afc5f33fd87bbc870cedd020d2a6dffa05d45ccd9241fbdd146db" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", "bitflags", "clap_derive", "clap_lex", "indexmap", - "lazy_static", + "once_cell", "strsim", "termcolor", - "textwrap 0.15.0", + "textwrap 0.16.2", ] [[package]] name = "clap_derive" -version = "3.1.7" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1" +checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ "heck", "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "clap_lex" -version = "0.1.1" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "189ddd3b5d32a70b35e7686054371742a937b0d99128e76dde6340210e966669" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" dependencies = [ "os_str_bytes", ] [[package]] name = "criterion" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" +checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" dependencies = [ "atty", "cast", - "clap 2.33.3", + "clap 2.34.0", "criterion-plot", "csv", "itertools", @@ -142,104 +136,83 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57" +checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" dependencies = [ "cast", "itertools", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" -version = "0.8.1" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.8" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "lazy_static", - "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.8" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" -dependencies = [ - "cfg-if", - "lazy_static", -] +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "csv" -version = "1.1.6" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" dependencies = [ - "bstr", "csv-core", - "itoa 0.4.8", + "itoa", "ryu", "serde", ] [[package]] name = "csv-core" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" dependencies = [ "memchr", ] [[package]] name = "either" -version = "1.6.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "half" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -252,9 +225,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown", @@ -262,31 +235,26 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itoa" -version = "0.4.8" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" -version = "0.3.57" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -302,82 +270,66 @@ name = "jsonformat-cli" version = "0.2.0" dependencies = [ "anyhow", - "clap 3.1.12", + "clap 3.2.25", "jsonformat", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.98" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "log" -version = "0.4.16" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" -dependencies = [ - "cfg-if", -] +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" [[package]] name = "memchr" -version = "2.4.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] -name = "num_cpus" -version = "1.13.1" +name = "once_cell" +version = "1.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] +checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "os_str_bytes" -version = "6.0.0" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "plotters" -version = "0.3.1" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -388,15 +340,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.2" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.1" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] @@ -410,7 +362,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] @@ -427,81 +379,82 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.37" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.18" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] [[package]] name = "rayon" -version = "1.5.2" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd249e82c21598a9a426a4e00dd7adc1d640b22445ec8545feef801d1a74c221" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ - "autocfg", - "crossbeam-deque", "either", "rayon-core", ] [[package]] name = "rayon-core" -version = "1.9.2" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f51245e1e62e1f1629cbfec37b5793bbabcaeb90f30e94d2ba03564687353e4" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] name = "regex" -version = "1.5.5" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" -version = "0.1.10" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" - -[[package]] -name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ - "semver", + "aho-corasick", + "memchr", + "regex-syntax", ] [[package]] -name = "ryu" -version = "1.0.9" +name = "regex-syntax" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -512,23 +465,14 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4" - [[package]] name = "serde" -version = "1.0.136" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] [[package]] name = "serde_cbor" @@ -542,22 +486,23 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.100", ] [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ - "itoa 1.0.1", + "itoa", + "memchr", "ryu", "serde", ] @@ -570,20 +515,31 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.91" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] name = "termcolor" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] @@ -599,9 +555,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.15.0" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" [[package]] name = "tinytemplate" @@ -614,64 +570,64 @@ dependencies = [ ] [[package]] -name = "unicode-width" -version = "0.1.8" +name = "unicode-ident" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] -name = "unicode-xid" -version = "0.2.2" +name = "unicode-width" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" -version = "2.3.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", - "winapi", "winapi-util", ] [[package]] name = "wasm-bindgen" -version = "0.2.80" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", + "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.80" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", - "lazy_static", "log", "proc-macro2", "quote", - "syn", + "syn 2.0.100", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.80" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -679,28 +635,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.80" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.100", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.80" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "web-sys" -version = "0.3.57" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -724,11 +683,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "winapi", + "windows-sys", ] [[package]] @@ -736,3 +695,76 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" From 0f16c73069915cb9963b1336555e8ff9c56fc934 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Fri, 21 Mar 2025 18:22:58 +0100 Subject: [PATCH 26/28] cleanup --- Cargo.toml | 7 +++---- jsonformat-cli/Cargo.toml | 7 +++---- src/lib.rs | 1 - 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7f4dd05..dcb66ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,12 +4,11 @@ members = [".", "jsonformat-cli"] [package] name = "jsonformat" version = "2.0.0" -authors = ["Nilstrieb "] -edition = "2021" +edition = "2024" license = "MIT" description = "Formats JSON extremely fast" -homepage = "https://github.com/Nilstrieb/jsonformat" -repository = "https://github.com/Nilstrieb/jsonformat" +homepage = "https://github.com/Noratrieb/jsonformat" +repository = "https://github.com/Noratrieb/jsonformat" readme = "README.md" keywords = ["json", "formatting"] categories = ["parser-implementations"] diff --git a/jsonformat-cli/Cargo.toml b/jsonformat-cli/Cargo.toml index 29de058..90a1ec4 100644 --- a/jsonformat-cli/Cargo.toml +++ b/jsonformat-cli/Cargo.toml @@ -1,12 +1,11 @@ [package] name = "jsonformat-cli" version = "0.2.0" -authors = ["Nilstrieb "] -edition = "2021" +edition = "2024" license = "MIT" description = "Formats JSON extremely fast" -homepage = "https://github.com/Nilstrieb/jsonformat" -repository = "https://github.com/Nilstrieb/jsonformat" +homepage = "https://github.com/Noratrieb/jsonformat" +repository = "https://github.com/Noratrieb/jsonformat" readme = "README.md" keywords = ["json", "formatting", "cli"] categories = ["command-line-utilities"] diff --git a/src/lib.rs b/src/lib.rs index 9362b99..79329ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,3 @@ -//! //! jsonformat is a library for formatting json. //! //! It does not do anything more than that, which makes it so fast. From 3b907e872ca68addf0e31069050f76f0207626af Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Fri, 21 Mar 2025 18:23:56 +0100 Subject: [PATCH 27/28] 2.1.0 --- CHANGELOG.md | 5 +++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fc3cf5..b35d1f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 2.1.0 + +- Strip `\r` from source (https://github.com/Noratrieb/jsonformat/pull/7) +- Various project cleanups + # 2.0.0 There are many changes, the two formatting functions have been renamed, `format_reader_writer` now takes diff --git a/Cargo.lock b/Cargo.lock index f4c72e9..b8dab01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -260,7 +260,7 @@ dependencies = [ [[package]] name = "jsonformat" -version = "2.0.0" +version = "2.1.0" dependencies = [ "criterion", ] diff --git a/Cargo.toml b/Cargo.toml index dcb66ab..dd3867a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = [".", "jsonformat-cli"] [package] name = "jsonformat" -version = "2.0.0" +version = "2.1.0" edition = "2024" license = "MIT" description = "Formats JSON extremely fast" From 5446fe2c508abed92b1066adb51f9a7e347180a1 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Fri, 21 Mar 2025 18:25:26 +0100 Subject: [PATCH 28/28] cli-1.0.0 --- Cargo.lock | 2 +- jsonformat-cli/Cargo.toml | 4 ++-- jsonformat-cli/README.md | 44 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 jsonformat-cli/README.md diff --git a/Cargo.lock b/Cargo.lock index b8dab01..fee8788 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -267,7 +267,7 @@ dependencies = [ [[package]] name = "jsonformat-cli" -version = "0.2.0" +version = "1.0.0" dependencies = [ "anyhow", "clap 3.2.25", diff --git a/jsonformat-cli/Cargo.toml b/jsonformat-cli/Cargo.toml index 90a1ec4..f7803f9 100644 --- a/jsonformat-cli/Cargo.toml +++ b/jsonformat-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jsonformat-cli" -version = "0.2.0" +version = "1.0.0" edition = "2024" license = "MIT" description = "Formats JSON extremely fast" @@ -14,7 +14,7 @@ categories = ["command-line-utilities"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -jsonformat = { path = "..", version = "2.0.0" } +jsonformat = { path = "..", version = "2.1.0" } clap = { version = "3.1.12", features = ["derive"] } anyhow = "1.0.57" diff --git a/jsonformat-cli/README.md b/jsonformat-cli/README.md new file mode 100644 index 0000000..7f3bab0 --- /dev/null +++ b/jsonformat-cli/README.md @@ -0,0 +1,44 @@ +# Extremely fast JSON formatter + +`jsonformat` is an extremely fast JSON formatter. + +It formats over 20MB of nested JSON in 60ms. + +## Library crate + +For the library crate, look at [docs.rs](https://docs.rs/jsonformat) + +## Binary Install +You need Rust installed on your system +`cargo install jsonformat-cli` + +## Binary Usage +``` +jsonformat-cli 0.2.0 +Formats JSON extremely fast + +USAGE: + jsonformat [OPTIONS] [INPUT] + +ARGS: + The input file + +OPTIONS: + -h, --help Print help information + -i, --indentation The indentation, s will replaced by a space and t by a tab. + ss is the default + -o, --output The output file + -V, --version Print version information +``` + +Reads from stdin if no file is supplied. +Outputs to stdout if no output file is specified. + +## Error handling +`jsonformat` does not report malformed json - it can't even fully know whether the json is actually malformed. +Malformed json is just formatted kind of incorrectly, with no data lost and no crashes. If you find one, open an issue, + + +## How? +`jsonformat` does not actually parse the json, it just loops through each character and keeps track of some flags. +It then copies these characters to the output buffer, adding and removing whitespace.