Unified · Split
| @@ -1429,12 +1429,12 @@ name = "gix-actor" · 1428 unmodified lines | |||
| 1429 | version = "0.30.0" | 1429 | version = "0.30.0" |
| 1430 | dependencies = [ | 1430 | dependencies = [ |
| 1431 | "bstr", | 1431 | "bstr", |
| 1432 | "btoi", | ||
| 1433 | "document-features", | 1432 | "document-features", |
| 1434 | "gix-date 0.8.3", | 1433 | "gix-date 0.8.3", |
| 1435 | "gix-features 0.38.0", | 1434 | "gix-features 0.38.0", |
| 1436 | "gix-hash 0.14.1", | 1435 | "gix-hash 0.14.1", |
| 1437 | "gix-testtools", | 1436 | "gix-testtools", |
| 1437 | "gix-utils 0.1.9", | ||
| 1438 | "itoa", | 1438 | "itoa", |
| 1439 | "pretty_assertions", | 1439 | "pretty_assertions", |
| 1440 | "serde", | 1440 | "serde", |
| @@ -2002,7 +2002,6 @@ version = "0.30.0" · 561 unmodified lines | |||
| 2002 | dependencies = [ | 2002 | dependencies = [ |
| 2003 | "bitflags 2.4.1", | 2003 | "bitflags 2.4.1", |
| 2004 | "bstr", | 2004 | "bstr", |
| 2005 | "btoi", | ||
| 2006 | "document-features", | 2005 | "document-features", |
| 2007 | "filetime", | 2006 | "filetime", |
| 2008 | "fnv", | 2007 | "fnv", |
| @@ -2013,6 +2012,7 @@ dependencies = [ · 4 unmodified lines | |||
| 2013 | "gix-lock 13.1.0", | 2012 | "gix-lock 13.1.0", |
| 2014 | "gix-object 0.41.0", | 2013 | "gix-object 0.41.0", |
| 2015 | "gix-traverse 0.37.0", | 2014 | "gix-traverse 0.37.0", |
| 2015 | "gix-utils 0.1.9", | ||
| 2016 | "hashbrown 0.14.3", | 2016 | "hashbrown 0.14.3", |
| 2017 | "itoa", | 2017 | "itoa", |
| 2018 | "libc", | 2018 | "libc", |
| @@ -2159,7 +2159,6 @@ name = "gix-object" · 140 unmodified lines | |||
| 2159 | version = "0.41.0" | 2159 | version = "0.41.0" |
| 2160 | dependencies = [ | 2160 | dependencies = [ |
| 2161 | "bstr", | 2161 | "bstr", |
| 2162 | "btoi", | ||
| 2163 | "criterion", | 2162 | "criterion", |
| 2164 | "document-features", | 2163 | "document-features", |
| 2165 | "gix-actor 0.30.0", | 2164 | "gix-actor 0.30.0", |
| @@ -2167,6 +2166,7 @@ dependencies = [ · 1 unmodified line | |||
| 2167 | "gix-features 0.38.0", | 2166 | "gix-features 0.38.0", |
| 2168 | "gix-hash 0.14.1", | 2167 | "gix-hash 0.14.1", |
| 2169 | "gix-testtools", | 2168 | "gix-testtools", |
| 2169 | "gix-utils 0.1.9", | ||
| 2170 | "gix-validate 0.8.3", | 2170 | "gix-validate 0.8.3", |
| 2171 | "itoa", | 2171 | "itoa", |
| 2172 | "pretty_assertions", | 2172 | "pretty_assertions", |
| @@ -2347,7 +2347,6 @@ dependencies = [ · 174 unmodified lines | |||
| 2347 | "async-std", | 2347 | "async-std", |
| 2348 | "async-trait", | 2348 | "async-trait", |
| 2349 | "bstr", | 2349 | "bstr", |
| 2350 | "btoi", | ||
| 2351 | "document-features", | 2350 | "document-features", |
| 2352 | "futures-io", | 2351 | "futures-io", |
| 2353 | "futures-lite 2.1.0", | 2352 | "futures-lite 2.1.0", |
| @@ -2358,6 +2357,7 @@ dependencies = [ · 4 unmodified lines | |||
| 2358 | "gix-packetline", | 2357 | "gix-packetline", |
| 2359 | "gix-testtools", | 2358 | "gix-testtools", |
| 2360 | "gix-transport", | 2359 | "gix-transport", |
| 2360 | "gix-utils 0.1.9", | ||
| 2361 | "maybe-async", | 2361 | "maybe-async", |
| 2362 | "serde", | 2362 | "serde", |
| 2363 | "thiserror", | 2363 | "thiserror", |
| @@ -2380,7 +2380,7 @@ name = "gix-quote" · 16 unmodified lines | |||
| 2380 | version = "0.4.10" | 2380 | version = "0.4.10" |
| 2381 | dependencies = [ | 2381 | dependencies = [ |
| 2382 | "bstr", | 2382 | "bstr", |
| 2383 | "btoi", | 2383 | "gix-utils 0.1.9", |
| 2384 | "thiserror", | 2384 | "thiserror", |
| 2385 | ] | 2385 | ] |
| 2386 | 2386 | ||
| @@ -19,19 +19,24 @@ serde = ["dep:serde", "bstr/serde", "gix-date/serde"] · 18 unmodified lines | |||
| 19 | [dependencies] | 19 | [dependencies] |
| 20 | gix-features = { version = "^0.38.0", path = "../gix-features", optional = true } | 20 | gix-features = { version = "^0.38.0", path = "../gix-features", optional = true } |
| 21 | gix-date = { version = "^0.8.3", path = "../gix-date" } | 21 | gix-date = { version = "^0.8.3", path = "../gix-date" } |
| 22 | gix-utils = { version = "^0.1.9", path = "../gix-utils" } | ||
| 22 | 23 | ||
| 23 | thiserror = "1.0.38" | 24 | thiserror = "1.0.38" |
| 24 | btoi = "0.4.2" | 25 | bstr = { version = "1.3.0", default-features = false, features = [ |
| 25 | bstr = { version = "1.3.0", default-features = false, features = ["std", "unicode"]} | 26 | "std", |
| 27 | "unicode", | ||
| 28 | ] } | ||
| 26 | winnow = { version = "0.6.0", features = ["simd"] } | 29 | winnow = { version = "0.6.0", features = ["simd"] } |
| 27 | itoa = "1.0.1" | 30 | itoa = "1.0.1" |
| 28 | serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"]} | 31 | serde = { version = "1.0.114", optional = true, default-features = false, features = [ |
| 32 | "derive", | ||
| 33 | ] } | ||
| 29 | 34 | ||
| 30 | document-features = { version = "0.2.0", optional = true } | 35 | document-features = { version = "0.2.0", optional = true } |
| 31 | 36 | ||
| 32 | [dev-dependencies] | 37 | [dev-dependencies] |
| 33 | pretty_assertions = "1.0.0" | 38 | pretty_assertions = "1.0.0" |
| 34 | gix-testtools = { path = "../tests/tools"} | 39 | gix-testtools = { path = "../tests/tools" } |
| 35 | gix-hash = { path = "../gix-hash" } | 40 | gix-hash = { path = "../gix-hash" } |
| 36 | 41 | ||
| 37 | [package.metadata.docs.rs] | 42 | [package.metadata.docs.rs] |
| @@ -1,7 +1,7 @@ | |||
| 1 | pub(crate) mod function { | 1 | pub(crate) mod function { |
| 2 | use bstr::ByteSlice; | 2 | use bstr::ByteSlice; |
| 3 | use btoi::btoi; | ||
| 4 | use gix_date::{time::Sign, OffsetInSeconds, SecondsSinceUnixEpoch, Time}; | 3 | use gix_date::{time::Sign, OffsetInSeconds, SecondsSinceUnixEpoch, Time}; |
| 4 | use gix_utils::btoi::btoi; | ||
| 5 | use winnow::{ | 5 | use winnow::{ |
| 6 | combinator::{alt, separated_pair, terminated}, | 6 | combinator::{alt, separated_pair, terminated}, |
| 7 | error::{AddContext, ParserError, StrContext}, | 7 | error::{AddContext, ParserError, StrContext}, |
| @@ -20,13 +20,17 @@ test = true · 19 unmodified lines | |||
| 20 | serde = ["dep:serde", "smallvec/serde", "gix-hash/serde"] | 20 | serde = ["dep:serde", "smallvec/serde", "gix-hash/serde"] |
| 21 | 21 | ||
| 22 | [dependencies] | 22 | [dependencies] |
| 23 | gix-features = { version = "^0.38.0", path = "../gix-features", features = ["rustsha1", "progress"] } | 23 | gix-features = { version = "^0.38.0", path = "../gix-features", features = [ |
| 24 | "rustsha1", | ||
| 25 | "progress", | ||
| 26 | ] } | ||
| 24 | gix-hash = { version = "^0.14.1", path = "../gix-hash" } | 27 | gix-hash = { version = "^0.14.1", path = "../gix-hash" } |
| 25 | gix-bitmap = { version = "^0.2.10", path = "../gix-bitmap" } | 28 | gix-bitmap = { version = "^0.2.10", path = "../gix-bitmap" } |
| 26 | gix-object = { version = "^0.41.0", path = "../gix-object" } | 29 | gix-object = { version = "^0.41.0", path = "../gix-object" } |
| 27 | gix-traverse = { version = "^0.37.0", path = "../gix-traverse" } | 30 | gix-traverse = { version = "^0.37.0", path = "../gix-traverse" } |
| 28 | gix-lock = { version = "^13.0.0", path = "../gix-lock" } | 31 | gix-lock = { version = "^13.0.0", path = "../gix-lock" } |
| 29 | gix-fs = { version = "^0.10.0", path = "../gix-fs" } | 32 | gix-fs = { version = "^0.10.0", path = "../gix-fs" } |
| 33 | gix-utils = { version = "^0.1.9", path = "../gix-utils" } | ||
| 30 | 34 | ||
| 31 | hashbrown = "0.14.3" | 35 | hashbrown = "0.14.3" |
| 32 | fnv = "1.0.7" | 36 | fnv = "1.0.7" |
| @@ -35,16 +39,20 @@ memmap2 = "0.9.0" · 2 unmodified lines | |||
| 35 | filetime = "0.2.15" | 39 | filetime = "0.2.15" |
| 36 | bstr = { version = "1.3.0", default-features = false } | 40 | bstr = { version = "1.3.0", default-features = false } |
| 37 | 41 | ||
| 38 | serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"] } | 42 | serde = { version = "1.0.114", optional = true, default-features = false, features = [ |
| 43 | "derive", | ||
| 44 | ] } | ||
| 39 | smallvec = "1.7.0" | 45 | smallvec = "1.7.0" |
| 40 | btoi = "0.4.3" | ||
| 41 | itoa = "1.0.3" | 46 | itoa = "1.0.3" |
| 42 | bitflags = "2" | 47 | bitflags = "2" |
| 43 | 48 | ||
| 44 | document-features = { version = "0.2.0", optional = true } | 49 | document-features = { version = "0.2.0", optional = true } |
| 45 | 50 | ||
| 46 | [target.'cfg(not(windows))'.dependencies] | 51 | [target.'cfg(not(windows))'.dependencies] |
| 47 | rustix = { version = "0.38.20", default-features = false, features = ["std", "fs"] } | 52 | rustix = { version = "0.38.20", default-features = false, features = [ |
| 53 | "std", | ||
| 54 | "fs", | ||
| 55 | ] } | ||
| 48 | libc = { version = "0.2.149" } | 56 | libc = { version = "0.2.149" } |
| 49 | 57 | ||
| 50 | [package.metadata.docs.rs] | 58 | [package.metadata.docs.rs] |
| @@ -22,10 +22,10 @@ fn one_recursive(data: &[u8], hash_len: usize) -> Option<(Tree, &[u8])> { · 21 unmodified lines | |||
| 22 | let (path, data) = split_at_byte_exclusive(data, 0)?; | 22 | let (path, data) = split_at_byte_exclusive(data, 0)?; |
| 23 | 23 | ||
| 24 | let (entry_count, data) = split_at_byte_exclusive(data, b' ')?; | 24 | let (entry_count, data) = split_at_byte_exclusive(data, b' ')?; |
| 25 | let num_entries: i32 = btoi::btoi(entry_count).ok()?; | 25 | let num_entries: i32 = gix_utils::btoi::btoi(entry_count).ok()?; |
| 26 | 26 | ||
| 27 | let (subtree_count, data) = split_at_byte_exclusive(data, b'\n')?; | 27 | let (subtree_count, data) = split_at_byte_exclusive(data, b'\n')?; |
| 28 | let subtree_count: usize = btoi::btou(subtree_count).ok()?; | 28 | let subtree_count: usize = gix_utils::btoi::btou(subtree_count).ok()?; |
| 29 | 29 | ||
| 30 | let (id, mut data) = if num_entries >= 0 { | 30 | let (id, mut data) = if num_entries >= 0 { |
| 31 | let (hash, data) = split_at_pos(data, hash_len)?; | 31 | let (hash, data) = split_at_pos(data, hash_len)?; |
| @@ -20,7 +20,13 @@ path = "./benches/decode_objects.rs" · 19 unmodified lines | |||
| 20 | 20 | ||
| 21 | [features] | 21 | [features] |
| 22 | ## Data structures implement `serde::Serialize` and `serde::Deserialize`. | 22 | ## Data structures implement `serde::Serialize` and `serde::Deserialize`. |
| 23 | serde = ["dep:serde", "bstr/serde", "smallvec/serde", "gix-hash/serde", "gix-actor/serde"] | 23 | serde = [ |
| 24 | "dep:serde", | ||
| 25 | "bstr/serde", | ||
| 26 | "smallvec/serde", | ||
| 27 | "gix-hash/serde", | ||
| 28 | "gix-actor/serde", | ||
| 29 | ] | ||
| 24 | ## When parsing objects by default errors will only be available on the granularity of success or failure, and with the above flag enabled | 30 | ## When parsing objects by default errors will only be available on the granularity of success or failure, and with the above flag enabled |
| 25 | ## details information about the error location will be collected. | 31 | ## details information about the error location will be collected. |
| 26 | ## Use it in applications which expect broken or invalid objects or for debugging purposes. Incorrectly formatted objects aren't at all | 32 | ## Use it in applications which expect broken or invalid objects or for debugging purposes. Incorrectly formatted objects aren't at all |
| @@ -28,28 +34,35 @@ serde = ["dep:serde", "bstr/serde", "smallvec/serde", "gix-hash/serde", "gix-act · 1 unmodified line | |||
| 28 | verbose-object-parsing-errors = ["winnow/std"] | 34 | verbose-object-parsing-errors = ["winnow/std"] |
| 29 | 35 | ||
| 30 | [dependencies] | 36 | [dependencies] |
| 31 | gix-features = { version = "^0.38.0", path = "../gix-features", features = ["rustsha1", "progress"] } | 37 | gix-features = { version = "^0.38.0", path = "../gix-features", features = [ |
| 38 | "rustsha1", | ||
| 39 | "progress", | ||
| 40 | ] } | ||
| 32 | gix-hash = { version = "^0.14.1", path = "../gix-hash" } | 41 | gix-hash = { version = "^0.14.1", path = "../gix-hash" } |
| 33 | gix-validate = { version = "^0.8.3", path = "../gix-validate" } | 42 | gix-validate = { version = "^0.8.3", path = "../gix-validate" } |
| 34 | gix-actor = { version = "^0.30.0", path = "../gix-actor" } | 43 | gix-actor = { version = "^0.30.0", path = "../gix-actor" } |
| 35 | gix-date = { version = "^0.8.3", path = "../gix-date" } | 44 | gix-date = { version = "^0.8.3", path = "../gix-date" } |
| 45 | gix-utils = { version = "^0.1.9", path = "../gix-utils" } | ||
| 36 | 46 | ||
| 37 | btoi = "0.4.2" | ||
| 38 | itoa = "1.0.1" | 47 | itoa = "1.0.1" |
| 39 | thiserror = "1.0.34" | 48 | thiserror = "1.0.34" |
| 40 | bstr = { version = "1.3.0", default-features = false, features = ["std", "unicode"] } | 49 | bstr = { version = "1.3.0", default-features = false, features = [ |
| 50 | "std", | ||
| 51 | "unicode", | ||
| 52 | ] } | ||
| 41 | winnow = { version = "0.6.0", features = ["simd"] } | 53 | winnow = { version = "0.6.0", features = ["simd"] } |
| 42 | smallvec = { version = "1.4.0", features = ["write"] } | 54 | smallvec = { version = "1.4.0", features = ["write"] } |
| 43 | serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"]} | 55 | serde = { version = "1.0.114", optional = true, default-features = false, features = [ |
| 56 | "derive", | ||
| 57 | ] } | ||
| 44 | 58 | ||
| 45 | document-features = { version = "0.2.0", optional = true } | 59 | document-features = { version = "0.2.0", optional = true } |
| 46 | 60 | ||
| 47 | [dev-dependencies] | 61 | [dev-dependencies] |
| 48 | criterion = "0.5.1" | 62 | criterion = "0.5.1" |
| 49 | pretty_assertions = "1.0.0" | 63 | pretty_assertions = "1.0.0" |
| 50 | gix-testtools = { path = "../tests/tools"} | 64 | gix-testtools = { path = "../tests/tools" } |
| 51 | 65 | ||
| 52 | [package.metadata.docs.rs] | 66 | [package.metadata.docs.rs] |
| 53 | all-features = true | 67 | all-features = true |
| 54 | features = ["document-features"] | 68 | features = ["document-features"] |
| 55 | |||
| @@ -358,7 +358,7 @@ pub mod decode { · 357 unmodified lines | |||
| 358 | pub enum LooseHeaderDecodeError { | 358 | pub enum LooseHeaderDecodeError { |
| 359 | #[error("{message}: {number:?}")] | 359 | #[error("{message}: {number:?}")] |
| 360 | ParseIntegerError { | 360 | ParseIntegerError { |
| 361 | source: btoi::ParseIntegerError, | 361 | source: gix_utils::btoi::ParseIntegerError, |
| 362 | message: &'static str, | 362 | message: &'static str, |
| 363 | number: bstr::BString, | 363 | number: bstr::BString, |
| 364 | }, | 364 | }, |
| @@ -383,7 +383,7 @@ pub mod decode { · 18 unmodified lines | |||
| 383 | message: "Did not find 0 byte in header", | 383 | message: "Did not find 0 byte in header", |
| 384 | })?; | 384 | })?; |
| 385 | let size_bytes = &input[kind_end + 1..size_end]; | 385 | let size_bytes = &input[kind_end + 1..size_end]; |
| 386 | let size = btoi::btoi(size_bytes).map_err(|source| ParseIntegerError { | 386 | let size = gix_utils::btoi::btoi(size_bytes).map_err(|source| ParseIntegerError { |
| 387 | source, | 387 | source, |
| 388 | message: "Object size in header could not be parsed", | 388 | message: "Object size in header could not be parsed", |
| 389 | number: size_bytes.into(), | 389 | number: size_bytes.into(), |
| @@ -23,7 +23,12 @@ doctest = false · 22 unmodified lines | |||
| 23 | ## If set, blocking command implementations are available and will use the blocking version of the `gix-transport` crate. | 23 | ## If set, blocking command implementations are available and will use the blocking version of the `gix-transport` crate. |
| 24 | blocking-client = ["gix-transport/blocking-client", "maybe-async/is_sync"] | 24 | blocking-client = ["gix-transport/blocking-client", "maybe-async/is_sync"] |
| 25 | ## As above, but provides async implementations instead. | 25 | ## As above, but provides async implementations instead. |
| 26 | async-client = ["gix-transport/async-client", "async-trait", "futures-io", "futures-lite"] | 26 | async-client = [ |
| 27 | "gix-transport/async-client", | ||
| 28 | "async-trait", | ||
| 29 | "futures-io", | ||
| 30 | "futures-lite", | ||
| 31 | ] | ||
| 27 | 32 | ||
| 28 | #! ### Other | 33 | #! ### Other |
| 29 | ## Data structures implement `serde::Serialize` and `serde::Deserialize`. | 34 | ## Data structures implement `serde::Serialize` and `serde::Deserialize`. |
| @@ -40,17 +45,24 @@ path = "tests/async-protocol.rs" · 10 unmodified lines | |||
| 40 | required-features = ["async-client"] | 45 | required-features = ["async-client"] |
| 41 | 46 | ||
| 42 | [dependencies] | 47 | [dependencies] |
| 43 | gix-features = { version = "^0.38.0", path = "../gix-features", features = ["progress"] } | 48 | gix-features = { version = "^0.38.0", path = "../gix-features", features = [ |
| 49 | "progress", | ||
| 50 | ] } | ||
| 44 | gix-transport = { version = "^0.41.0", path = "../gix-transport" } | 51 | gix-transport = { version = "^0.41.0", path = "../gix-transport" } |
| 45 | gix-hash = { version = "^0.14.1", path = "../gix-hash" } | 52 | gix-hash = { version = "^0.14.1", path = "../gix-hash" } |
| 46 | gix-date = { version = "^0.8.3", path = "../gix-date" } | 53 | gix-date = { version = "^0.8.3", path = "../gix-date" } |
| 47 | gix-credentials = { version = "^0.24.0", path = "../gix-credentials" } | 54 | gix-credentials = { version = "^0.24.0", path = "../gix-credentials" } |
| 55 | gix-utils = { version = "^0.1.9", path = "../gix-utils" } | ||
| 48 | 56 | ||
| 49 | thiserror = "1.0.32" | 57 | thiserror = "1.0.32" |
| 50 | serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"]} | 58 | serde = { version = "1.0.114", optional = true, default-features = false, features = [ |
| 51 | bstr = { version = "1.3.0", default-features = false, features = ["std", "unicode"] } | 59 | "derive", |
| 60 | ] } | ||
| 61 | bstr = { version = "1.3.0", default-features = false, features = [ | ||
| 62 | "std", | ||
| 63 | "unicode", | ||
| 64 | ] } | ||
| 52 | winnow = { version = "0.6.0", features = ["simd"] } | 65 | winnow = { version = "0.6.0", features = ["simd"] } |
| 53 | btoi = "0.4.2" | ||
| 54 | 66 | ||
| 55 | # for async-client | 67 | # for async-client |
| 56 | async-trait = { version = "0.1.51", optional = true } | 68 | async-trait = { version = "0.1.51", optional = true } |
| @@ -62,7 +74,7 @@ document-features = { version = "0.2.0", optional = true } · 5 unmodified lines | |||
| 62 | 74 | ||
| 63 | [dev-dependencies] | 75 | [dev-dependencies] |
| 64 | async-std = { version = "1.9.0", features = ["attributes"] } | 76 | async-std = { version = "1.9.0", features = ["attributes"] } |
| 65 | gix-packetline = { path = "../gix-packetline" ,version = "^0.17.3" } | 77 | gix-packetline = { path = "../gix-packetline", version = "^0.17.3" } |
| 66 | gix-testtools = { path = "../tests/tools" } | 78 | gix-testtools = { path = "../tests/tools" } |
| 67 | 79 | ||
| 68 | [package.metadata.docs.rs] | 80 | [package.metadata.docs.rs] |
| @@ -75,7 +75,7 @@ impl<'a> RemoteProgress<'a> { · 74 unmodified lines | |||
| 75 | 75 | ||
| 76 | fn parse_number(i: &mut &[u8]) -> PResult<usize, ()> { | 76 | fn parse_number(i: &mut &[u8]) -> PResult<usize, ()> { |
| 77 | take_till(0.., |c: u8| !c.is_ascii_digit()) | 77 | take_till(0.., |c: u8| !c.is_ascii_digit()) |
| 78 | .try_map(btoi::btoi) | 78 | .try_map(gix_utils::btoi::btoi) |
| 79 | .parse_next(i) | 79 | .parse_next(i) |
| 80 | } | 80 | } |
| 81 | 81 | ||
| @@ -13,6 +13,7 @@ include = ["src/**/*", "LICENSE-*"] · 12 unmodified lines | |||
| 13 | doctest = false | 13 | doctest = false |
| 14 | 14 | ||
| 15 | [dependencies] | 15 | [dependencies] |
| 16 | bstr = { version = "1.3.0", default-features = false, features = ["std"]} | 16 | gix-utils = { version = "^0.1.9", path = "../gix-utils" } |
| 17 | |||
| 18 | bstr = { version = "1.3.0", default-features = false, features = ["std"] } | ||
| 17 | thiserror = "1.0.38" | 19 | thiserror = "1.0.38" |
| 18 | btoi = "0.4.2" | ||
| @@ -89,7 +89,8 @@ pub fn undo(input: &BStr) -> Result<(Cow<'_, BStr>, usize), undo::Error> { · 88 unmodified lines | |||
| 89 | })? | 89 | })? |
| 90 | .read_exact(&mut buf[1..]) | 90 | .read_exact(&mut buf[1..]) |
| 91 | .expect("impossible to fail as numbers match"); | 91 | .expect("impossible to fail as numbers match"); |
| 92 | let byte = btoi::btou_radix(&buf, 8).map_err(|e| undo::Error::new(e, original))?; | 92 | let byte = |
| 93 | gix_utils::btoi::btou_radix(&buf, 8).map_err(|e| undo::Error::new(e, original))?; | ||
| 93 | out.push(byte); | 94 | out.push(byte); |
| 94 | input = &input[2..]; | 95 | input = &input[2..]; |
| 95 | consumed += 2; | 96 | consumed += 2; |
| @@ -0,0 +1,392 @@ | |||
| 1 | // ported from https://github.com/niklasf/rust-btoi version 0.4.3 | ||
| 2 | // see https://github.com/Byron/gitoxide/issues/729#issuecomment-1941515655 | ||
| 3 | |||
| 4 | /// An error that can occur when parsing an integer. | ||
| 5 | /// | ||
| 6 | /// * No digits | ||
| 7 | /// * Invalid digit | ||
| 8 | /// * Overflow | ||
| 9 | /// * Underflow | ||
| 10 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
| 11 | pub struct ParseIntegerError { | ||
| 12 | kind: ErrorKind, | ||
| 13 | } | ||
| 14 | |||
| 15 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
| 16 | enum ErrorKind { | ||
| 17 | Empty, | ||
| 18 | InvalidDigit, | ||
| 19 | Overflow, | ||
| 20 | Underflow, | ||
| 21 | } | ||
| 22 | |||
| 23 | impl ParseIntegerError { | ||
| 24 | fn desc(&self) -> &str { | ||
| 25 | match self.kind { | ||
| 26 | ErrorKind::Empty => "cannot parse integer without digits", | ||
| 27 | ErrorKind::InvalidDigit => "invalid digit found in slice", | ||
| 28 | ErrorKind::Overflow => "number too large to fit in target type", | ||
| 29 | ErrorKind::Underflow => "number too small to fit in target type", | ||
| 30 | } | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | impl std::fmt::Display for ParseIntegerError { | ||
| 35 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
| 36 | self.desc().fmt(f) | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | impl std::error::Error for ParseIntegerError { | ||
| 41 | fn description(&self) -> &str { | ||
| 42 | self.desc() | ||
| 43 | } | ||
| 44 | } | ||
| 45 | /// minimal subset of traits used by btoi_radix and btou_radix | ||
| 46 | pub trait MinNumTraits: Sized + Copy { | ||
| 47 | /// | ||
| 48 | fn from_u32(n: u32) -> Option<Self>; | ||
| 49 | /// | ||
| 50 | fn zero() -> Self; | ||
| 51 | /// | ||
| 52 | fn checked_mul(self, v: Self) -> Option<Self>; | ||
| 53 | /// | ||
| 54 | fn checked_add(self, v: Self) -> Option<Self>; | ||
| 55 | /// | ||
| 56 | fn checked_sub(self, v: Self) -> Option<Self>; | ||
| 57 | } | ||
| 58 | |||
| 59 | impl MinNumTraits for i64 { | ||
| 60 | fn from_u32(n: u32) -> Option<i64> { | ||
| 61 | Some(n.into()) | ||
| 62 | } | ||
| 63 | |||
| 64 | fn zero() -> Self { | ||
| 65 | 0 | ||
| 66 | } | ||
| 67 | |||
| 68 | fn checked_mul(self, v: i64) -> Option<i64> { | ||
| 69 | i64::checked_mul(self, v) | ||
| 70 | } | ||
| 71 | |||
| 72 | fn checked_add(self, v: i64) -> Option<i64> { | ||
| 73 | i64::checked_add(self, v) | ||
| 74 | } | ||
| 75 | |||
| 76 | fn checked_sub(self, v: i64) -> Option<i64> { | ||
| 77 | i64::checked_sub(self, v) | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | impl MinNumTraits for u64 { | ||
| 82 | fn from_u32(n: u32) -> Option<u64> { | ||
| 83 | Some(n.into()) | ||
| 84 | } | ||
| 85 | |||
| 86 | fn zero() -> Self { | ||
| 87 | 0 | ||
| 88 | } | ||
| 89 | |||
| 90 | fn checked_mul(self, v: u64) -> Option<u64> { | ||
| 91 | u64::checked_mul(self, v) | ||
| 92 | } | ||
| 93 | |||
| 94 | fn checked_add(self, v: u64) -> Option<u64> { | ||
| 95 | u64::checked_add(self, v) | ||
| 96 | } | ||
| 97 | |||
| 98 | fn checked_sub(self, v: u64) -> Option<u64> { | ||
| 99 | u64::checked_sub(self, v) | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | impl MinNumTraits for usize { | ||
| 104 | fn from_u32(n: u32) -> Option<usize> { | ||
| 105 | n.try_into().ok() | ||
| 106 | } | ||
| 107 | |||
| 108 | fn zero() -> Self { | ||
| 109 | 0 | ||
| 110 | } | ||
| 111 | |||
| 112 | fn checked_mul(self, v: usize) -> Option<usize> { | ||
| 113 | usize::checked_mul(self, v) | ||
| 114 | } | ||
| 115 | |||
| 116 | fn checked_add(self, v: usize) -> Option<usize> { | ||
| 117 | usize::checked_add(self, v) | ||
| 118 | } | ||
| 119 | |||
| 120 | fn checked_sub(self, v: usize) -> Option<usize> { | ||
| 121 | usize::checked_sub(self, v) | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | impl MinNumTraits for i32 { | ||
| 126 | fn from_u32(n: u32) -> Option<Self> { | ||
| 127 | n.try_into().ok() | ||
| 128 | } | ||
| 129 | |||
| 130 | fn zero() -> Self { | ||
| 131 | 0 | ||
| 132 | } | ||
| 133 | |||
| 134 | fn checked_mul(self, v: i32) -> Option<i32> { | ||
| 135 | i32::checked_mul(self, v) | ||
| 136 | } | ||
| 137 | |||
| 138 | fn checked_add(self, v: i32) -> Option<i32> { | ||
| 139 | i32::checked_add(self, v) | ||
| 140 | } | ||
| 141 | |||
| 142 | fn checked_sub(self, v: i32) -> Option<i32> { | ||
| 143 | i32::checked_sub(self, v) | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | impl MinNumTraits for u8 { | ||
| 148 | fn from_u32(n: u32) -> Option<Self> { | ||
| 149 | n.try_into().ok() | ||
| 150 | } | ||
| 151 | |||
| 152 | fn zero() -> Self { | ||
| 153 | 0 | ||
| 154 | } | ||
| 155 | |||
| 156 | fn checked_mul(self, v: u8) -> Option<u8> { | ||
| 157 | u8::checked_mul(self, v) | ||
| 158 | } | ||
| 159 | |||
| 160 | fn checked_add(self, v: u8) -> Option<u8> { | ||
| 161 | u8::checked_add(self, v) | ||
| 162 | } | ||
| 163 | |||
| 164 | fn checked_sub(self, v: u8) -> Option<u8> { | ||
| 165 | u8::checked_sub(self, v) | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | /// Converts a byte slice to an integer. Signs are not allowed. | ||
| 170 | /// | ||
| 171 | /// # Errors | ||
| 172 | /// | ||
| 173 | /// Returns [`ParseIntegerError`] for any of the following conditions: | ||
| 174 | /// | ||
| 175 | /// * `bytes` is empty | ||
| 176 | /// * not all characters of `bytes` are `0-9` | ||
| 177 | /// * the number overflows `I` | ||
| 178 | /// | ||
| 179 | /// # Panics | ||
| 180 | /// | ||
| 181 | /// Panics in the pathological case that there is no representation of `10` | ||
| 182 | /// in `I`. | ||
| 183 | /// | ||
| 184 | /// # Examples | ||
| 185 | /// | ||
| 186 | /// ``` | ||
| 187 | /// # use btoi::btou; | ||
| 188 | /// assert_eq!(Ok(12345), btou(b"12345")); | ||
| 189 | /// assert!(btou::<u8>(b"+1").is_err()); // only btoi allows signs | ||
| 190 | /// assert!(btou::<u8>(b"256").is_err()); // overflow | ||
| 191 | /// ``` | ||
| 192 | /// | ||
| 193 | /// [`ParseIntegerError`]: struct.ParseIntegerError.html | ||
| 194 | #[track_caller] | ||
| 195 | pub fn btou<I: MinNumTraits>(bytes: &[u8]) -> Result<I, ParseIntegerError> { | ||
| 196 | btou_radix(bytes, 10) | ||
| 197 | } | ||
| 198 | |||
| 199 | /// Converts a byte slice in a given base to an integer. Signs are not allowed. | ||
| 200 | /// | ||
| 201 | /// # Errors | ||
| 202 | /// | ||
| 203 | /// Returns [`ParseIntegerError`] for any of the following conditions: | ||
| 204 | /// | ||
| 205 | /// * `bytes` is empty | ||
| 206 | /// * not all characters of `bytes` are `0-9`, `a-z` or `A-Z` | ||
| 207 | /// * not all characters refer to digits in the given `radix` | ||
| 208 | /// * the number overflows `I` | ||
| 209 | /// | ||
| 210 | /// # Panics | ||
| 211 | /// | ||
| 212 | /// Panics if `radix` is not in the range `2..=36` (or in the pathological | ||
| 213 | /// case that there is no representation of `radix` in `I`). | ||
| 214 | /// | ||
| 215 | /// # Examples | ||
| 216 | /// | ||
| 217 | /// ``` | ||
| 218 | /// # use btoi::btou_radix; | ||
| 219 | /// assert_eq!(Ok(255), btou_radix(b"ff", 16)); | ||
| 220 | /// assert_eq!(Ok(42), btou_radix(b"101010", 2)); | ||
| 221 | /// ``` | ||
| 222 | /// | ||
| 223 | /// [`ParseIntegerError`]: struct.ParseIntegerError.html | ||
| 224 | pub fn btou_radix<I: MinNumTraits>(bytes: &[u8], radix: u32) -> Result<I, ParseIntegerError> { | ||
| 225 | assert!( | ||
| 226 | (2..=36).contains(&radix), | ||
| 227 | "radix must lie in the range 2..=36, found {}", | ||
| 228 | radix | ||
| 229 | ); | ||
| 230 | |||
| 231 | let base = I::from_u32(radix).expect("radix can be represented as integer"); | ||
| 232 | |||
| 233 | if bytes.is_empty() { | ||
| 234 | return Err(ParseIntegerError { kind: ErrorKind::Empty }); | ||
| 235 | } | ||
| 236 | |||
| 237 | let mut result = I::zero(); | ||
| 238 | |||
| 239 | for &digit in bytes { | ||
| 240 | let x = match char::from(digit).to_digit(radix).and_then(I::from_u32) { | ||
| 241 | Some(x) => x, | ||
| 242 | None => { | ||
| 243 | return Err(ParseIntegerError { | ||
| 244 | kind: ErrorKind::InvalidDigit, | ||
| 245 | }) | ||
| 246 | } | ||
| 247 | }; | ||
| 248 | result = match result.checked_mul(base) { | ||
| 249 | Some(result) => result, | ||
| 250 | None => { | ||
| 251 | return Err(ParseIntegerError { | ||
| 252 | kind: ErrorKind::Overflow, | ||
| 253 | }) | ||
| 254 | } | ||
| 255 | }; | ||
| 256 | result = match result.checked_add(x) { | ||
| 257 | Some(result) => result, | ||
| 258 | None => { | ||
| 259 | return Err(ParseIntegerError { | ||
| 260 | kind: ErrorKind::Overflow, | ||
| 261 | }) | ||
| 262 | } | ||
| 263 | }; | ||
| 264 | } | ||
| 265 | |||
| 266 | Ok(result) | ||
| 267 | } | ||
| 268 | |||
| 269 | /// Converts a byte slice to an integer. | ||
| 270 | /// | ||
| 271 | /// Like [`btou`], but numbers may optionally start with a sign (`-` or `+`). | ||
| 272 | /// | ||
| 273 | /// # Errors | ||
| 274 | /// | ||
| 275 | /// Returns [`ParseIntegerError`] for any of the following conditions: | ||
| 276 | /// | ||
| 277 | /// * `bytes` has no digits | ||
| 278 | /// * not all characters of `bytes` are `0-9`, excluding an optional leading | ||
| 279 | /// sign | ||
| 280 | /// * the number overflows or underflows `I` | ||
| 281 | /// | ||
| 282 | /// # Panics | ||
| 283 | /// | ||
| 284 | /// Panics in the pathological case that there is no representation of `10` | ||
| 285 | /// in `I`. | ||
| 286 | /// | ||
| 287 | /// # Examples | ||
| 288 | /// | ||
| 289 | /// ``` | ||
| 290 | /// # use btoi::btoi; | ||
| 291 | /// assert_eq!(Ok(123), btoi(b"123")); | ||
| 292 | /// assert_eq!(Ok(123), btoi(b"+123")); | ||
| 293 | /// assert_eq!(Ok(-123), btoi(b"-123")); | ||
| 294 | /// | ||
| 295 | /// assert!(btoi::<i16>(b"123456789").is_err()); // overflow | ||
| 296 | /// assert!(btoi::<u32>(b"-1").is_err()); // underflow | ||
| 297 | /// | ||
| 298 | /// assert!(btoi::<i32>(b" 42").is_err()); // leading space | ||
| 299 | /// ``` | ||
| 300 | /// | ||
| 301 | /// [`btou`]: fn.btou.html | ||
| 302 | /// [`ParseIntegerError`]: struct.ParseIntegerError.html | ||
| 303 | pub fn btoi<I: MinNumTraits>(bytes: &[u8]) -> Result<I, ParseIntegerError> { | ||
| 304 | btoi_radix(bytes, 10) | ||
| 305 | } | ||
| 306 | |||
| 307 | /// Converts a byte slice in a given base to an integer. | ||
| 308 | /// | ||
| 309 | /// Like [`btou_radix`], but numbers may optionally start with a sign | ||
| 310 | /// (`-` or `+`). | ||
| 311 | /// | ||
| 312 | /// # Errors | ||
| 313 | /// | ||
| 314 | /// Returns [`ParseIntegerError`] for any of the following conditions: | ||
| 315 | /// | ||
| 316 | /// * `bytes` has no digits | ||
| 317 | /// * not all characters of `bytes` are `0-9`, `a-z`, `A-Z`, exluding an | ||
| 318 | /// optional leading sign | ||
| 319 | /// * not all characters refer to digits in the given `radix`, exluding an | ||
| 320 | /// optional leading sign | ||
| 321 | /// * the number overflows or underflows `I` | ||
| 322 | /// | ||
| 323 | /// # Panics | ||
| 324 | /// | ||
| 325 | /// Panics if `radix` is not in the range `2..=36` (or in the pathological | ||
| 326 | /// case that there is no representation of `radix` in `I`). | ||
| 327 | /// | ||
| 328 | /// # Examples | ||
| 329 | /// | ||
| 330 | /// ``` | ||
| 331 | /// # use btoi::btoi_radix; | ||
| 332 | /// assert_eq!(Ok(10), btoi_radix(b"a", 16)); | ||
| 333 | /// assert_eq!(Ok(10), btoi_radix(b"+a", 16)); | ||
| 334 | /// assert_eq!(Ok(-42), btoi_radix(b"-101010", 2)); | ||
| 335 | /// ``` | ||
| 336 | /// | ||
| 337 | /// [`btou_radix`]: fn.btou_radix.html | ||
| 338 | /// [`ParseIntegerError`]: struct.ParseIntegerError.html | ||
| 339 | fn btoi_radix<I: MinNumTraits>(bytes: &[u8], radix: u32) -> Result<I, ParseIntegerError> { | ||
| 340 | assert!( | ||
| 341 | (2..=36).contains(&radix), | ||
| 342 | "radix must lie in the range 2..=36, found {}", | ||
| 343 | radix | ||
| 344 | ); | ||
| 345 | |||
| 346 | let base = I::from_u32(radix).expect("radix can be represented as integer"); | ||
| 347 | |||
| 348 | if bytes.is_empty() { | ||
| 349 | return Err(ParseIntegerError { kind: ErrorKind::Empty }); | ||
| 350 | } | ||
| 351 | |||
| 352 | let digits = match bytes[0] { | ||
| 353 | b'+' => return btou_radix(&bytes[1..], radix), | ||
| 354 | b'-' => &bytes[1..], | ||
| 355 | _ => return btou_radix(bytes, radix), | ||
| 356 | }; | ||
| 357 | |||
| 358 | if digits.is_empty() { | ||
| 359 | return Err(ParseIntegerError { kind: ErrorKind::Empty }); | ||
| 360 | } | ||
| 361 | |||
| 362 | let mut result = I::zero(); | ||
| 363 | |||
| 364 | for &digit in digits { | ||
| 365 | let x = match char::from(digit).to_digit(radix).and_then(I::from_u32) { | ||
| 366 | Some(x) => x, | ||
| 367 | None => { | ||
| 368 | return Err(ParseIntegerError { | ||
| 369 | kind: ErrorKind::InvalidDigit, | ||
| 370 | }) | ||
| 371 | } | ||
| 372 | }; | ||
| 373 | result = match result.checked_mul(base) { | ||
| 374 | Some(result) => result, | ||
| 375 | None => { | ||
| 376 | return Err(ParseIntegerError { | ||
| 377 | kind: ErrorKind::Underflow, | ||
| 378 | }) | ||
| 379 | } | ||
| 380 | }; | ||
| 381 | result = match result.checked_sub(x) { | ||
| 382 | Some(result) => result, | ||
| 383 | None => { | ||
| 384 | return Err(ParseIntegerError { | ||
| 385 | kind: ErrorKind::Underflow, | ||
| 386 | }) | ||
| 387 | } | ||
| 388 | }; | ||
| 389 | } | ||
| 390 | |||
| 391 | Ok(result) | ||
| 392 | } | ||
| @@ -13,6 +13,9 @@ pub mod buffers; · 12 unmodified lines | |||
| 13 | /// | 13 | /// |
| 14 | pub mod str; | 14 | pub mod str; |
| 15 | 15 | ||
| 16 | /// | ||
| 17 | pub mod btoi; | ||
| 18 | |||
| 16 | /// A utility to do buffer-swapping with. | 19 | /// A utility to do buffer-swapping with. |
| 17 | /// | 20 | /// |
| 18 | /// Use `src` to read from and `dest` to write to, and after actually changing data, call [Buffers::swap()]. | 21 | /// Use `src` to read from and `dest` to write to, and after actually changing data, call [Buffers::swap()]. |