├── .gitignore ├── .gitattributes ├── .vscode └── settings.json ├── gen ├── Cargo.toml └── src │ └── main.rs ├── src ├── quickcheck1.rs ├── proptest1.rs ├── arbitrary1.rs ├── mirror_std │ ├── cmp.rs │ ├── try_from.rs │ ├── partial_eq.rs │ └── from.rs ├── serde1.rs ├── schemars1.rs ├── schemars09.rs ├── schemars08.rs ├── array.rs ├── slice.rs ├── iter.rs ├── lib.rs └── vec.rs ├── tests ├── try_from.rs ├── partial_eq.rs └── from.rs ├── Cargo.toml ├── README.md ├── benches └── against-nonempty.rs └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.ipynb linguist-generated=true 2 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.cargo.features": "all" 3 | } 4 | -------------------------------------------------------------------------------- /gen/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gen" 3 | version = "0.0.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [dependencies] 8 | anyhow = "1.0.82" 9 | clap = { version = "4.5.4", features = ["derive"] } 10 | prettyplease = "0.2.19" 11 | proc-macro2 = { version = "1.0.81", default-features = false } 12 | quote = { version = "1.0.36", default-features = false } 13 | regex = "1.10.4" 14 | scraper = "0.19.0" 15 | syn = { version = "2.0.60", features = ["extra-traits", "visit-mut"] } 16 | syn-miette = "0.3.0" 17 | ureq = "2.9.6" 18 | owo-colors = "4.0.0" 19 | -------------------------------------------------------------------------------- /src/quickcheck1.rs: -------------------------------------------------------------------------------- 1 | use crate::{Slice, Vec}; 2 | use quickcheck1::Arbitrary; 3 | 4 | impl Arbitrary for Vec 5 | where 6 | T: Arbitrary, 7 | { 8 | fn arbitrary(g: &mut quickcheck1::Gen) -> Self { 9 | let mut it = Vec::of(T::arbitrary(g)); 10 | it.extend(alloc::vec::Vec::arbitrary(g)); 11 | it 12 | } 13 | fn shrink(&self) -> Box> { 14 | let raw = self.clone().into_vec(); 15 | Box::new(Arbitrary::shrink(&raw).flat_map(Vec::new)) 16 | } 17 | } 18 | 19 | impl Arbitrary for Box> 20 | where 21 | T: Arbitrary, 22 | { 23 | fn arbitrary(g: &mut quickcheck1::Gen) -> Self { 24 | let mut it = Vec::of(T::arbitrary(g)); 25 | it.extend(alloc::vec::Vec::arbitrary(g)); 26 | it.into_boxed_slice() 27 | } 28 | fn shrink(&self) -> Box> { 29 | let raw = Vec::from(self.clone()); 30 | Box::new(Arbitrary::shrink(&raw).map(Self::from)) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/proptest1.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "alloc")] 2 | use core::fmt::Debug; 3 | 4 | use crate::{Slice, Vec}; 5 | 6 | use proptest1::{ 7 | arbitrary::Arbitrary, 8 | sample::SizeRange, 9 | strategy::{FilterMap, Map, Strategy as _}, 10 | }; 11 | 12 | impl Arbitrary for Vec 13 | where 14 | T: Arbitrary + Debug, 15 | { 16 | type Parameters = (SizeRange, ::Parameters); 17 | 18 | fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { 19 | alloc::vec::Vec::::arbitrary_with(args) 20 | .prop_filter_map("vec was empty", |it| Vec::new(it).ok()) 21 | } 22 | 23 | type Strategy = FilterMap< 24 | as Arbitrary>::Strategy, 25 | fn(alloc::vec::Vec) -> Option>, 26 | >; 27 | } 28 | 29 | impl Arbitrary for Box> 30 | where 31 | T: Arbitrary + Debug, 32 | { 33 | type Parameters = (SizeRange, ::Parameters); 34 | 35 | fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { 36 | Vec::arbitrary_with(args).prop_map(Into::into) 37 | } 38 | 39 | type Strategy = Map< as Arbitrary>::Strategy, fn(Vec) -> Box>>; 40 | } 41 | -------------------------------------------------------------------------------- /src/arbitrary1.rs: -------------------------------------------------------------------------------- 1 | use arbitrary1::Arbitrary; 2 | 3 | use crate::{Slice, Vec}; 4 | 5 | impl<'a> Arbitrary<'a> for &'a Slice { 6 | fn arbitrary(u: &mut arbitrary1::Unstructured<'a>) -> arbitrary1::Result { 7 | let len = u.arbitrary_len::()?.saturating_add(1); 8 | Ok(Slice::new(u.bytes(len)?).expect("`len` was non-zero")) 9 | } 10 | 11 | fn size_hint(depth: usize) -> (usize, Option) { 12 | let _ = depth; 13 | (1, None) 14 | } 15 | } 16 | 17 | impl<'a, T> Arbitrary<'a> for Vec 18 | where 19 | T: Arbitrary<'a>, 20 | { 21 | fn arbitrary(u: &mut arbitrary1::Unstructured<'a>) -> arbitrary1::Result { 22 | let mut it = Vec::of(u.arbitrary::()?); 23 | for item in u.arbitrary_iter()? { 24 | it.push(item?) 25 | } 26 | Ok(it) 27 | } 28 | 29 | fn size_hint(depth: usize) -> (usize, Option) { 30 | let _ = depth; 31 | (1, None) 32 | } 33 | } 34 | 35 | impl<'a, T> Arbitrary<'a> for Box> 36 | where 37 | T: Arbitrary<'a>, 38 | { 39 | fn arbitrary(u: &mut arbitrary1::Unstructured<'a>) -> arbitrary1::Result { 40 | Ok(Vec::arbitrary(u)?.into_boxed_slice()) 41 | } 42 | 43 | fn size_hint(depth: usize) -> (usize, Option) { 44 | let _ = depth; 45 | (1, None) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/mirror_std/cmp.rs: -------------------------------------------------------------------------------- 1 | //! There aren't that many implementations in [`std`]... 2 | 3 | use crate::{Array, Slice}; 4 | use core::cmp::Ordering; 5 | 6 | #[cfg(feature = "alloc")] 7 | use crate::Vec; 8 | 9 | impl PartialOrd for Slice 10 | where 11 | T: PartialOrd, 12 | { 13 | fn partial_cmp(&self, other: &Self) -> Option { 14 | <[_] as PartialOrd>::partial_cmp(self, other) 15 | } 16 | } 17 | 18 | impl Ord for Slice 19 | where 20 | T: Ord, 21 | { 22 | fn cmp(&self, other: &Self) -> Ordering { 23 | <[_] as Ord>::cmp(self, other) 24 | } 25 | } 26 | 27 | impl PartialOrd for Array 28 | where 29 | T: PartialOrd, 30 | { 31 | fn partial_cmp(&self, other: &Self) -> Option { 32 | <[_] as PartialOrd>::partial_cmp(self, other) 33 | } 34 | } 35 | impl Ord for Array 36 | where 37 | T: Ord, 38 | { 39 | fn cmp(&self, other: &Self) -> Ordering { 40 | <[_] as Ord>::cmp(self, other) 41 | } 42 | } 43 | 44 | #[cfg(feature = "alloc")] 45 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 46 | impl PartialOrd> for Vec 47 | where 48 | T: PartialOrd, 49 | { 50 | fn partial_cmp(&self, other: &Vec) -> Option { 51 | <[_] as PartialOrd>::partial_cmp(self, other) 52 | } 53 | } 54 | 55 | #[cfg(feature = "alloc")] 56 | impl Ord for Vec 57 | where 58 | T: Ord, 59 | { 60 | fn cmp(&self, other: &Self) -> Ordering { 61 | <[_] as Ord>::cmp(self, other) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/serde1.rs: -------------------------------------------------------------------------------- 1 | use serde1::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer}; 2 | 3 | use crate::Slice; 4 | #[cfg(feature = "alloc")] 5 | use { 6 | crate::{Error, Vec}, 7 | alloc::boxed::Box, 8 | }; 9 | 10 | impl<'de: 'a, 'a> Deserialize<'de> for &'a Slice { 11 | fn deserialize(deserializer: D) -> Result 12 | where 13 | D: Deserializer<'de>, 14 | { 15 | <&Slice>::try_from(<&[u8]>::deserialize(deserializer)?).map_err(D::Error::custom) 16 | } 17 | } 18 | 19 | impl Serialize for Slice 20 | where 21 | T: Serialize, 22 | { 23 | fn serialize(&self, serializer: S) -> Result 24 | where 25 | S: Serializer, 26 | { 27 | self.as_slice().serialize(serializer) 28 | } 29 | } 30 | 31 | #[cfg(feature = "alloc")] 32 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 33 | impl<'de, T> Deserialize<'de> for Box> 34 | where 35 | T: Deserialize<'de>, 36 | { 37 | fn deserialize(deserializer: D) -> Result 38 | where 39 | D: Deserializer<'de>, 40 | { 41 | >>::try_from(>::deserialize(deserializer)?).map_err(D::Error::custom) 42 | } 43 | } 44 | 45 | #[cfg(feature = "alloc")] 46 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 47 | impl<'de, T> Deserialize<'de> for Vec 48 | where 49 | T: Deserialize<'de>, 50 | { 51 | fn deserialize(deserializer: D) -> Result 52 | where 53 | D: Deserializer<'de>, 54 | { 55 | Vec::new(alloc::vec::Vec::deserialize(deserializer)?) 56 | .map_err(|_| D::Error::custom(Error(()))) 57 | } 58 | } 59 | #[cfg(feature = "alloc")] 60 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 61 | impl Serialize for Vec 62 | where 63 | T: Serialize, 64 | { 65 | fn serialize(&self, serializer: S) -> Result 66 | where 67 | S: Serializer, 68 | { 69 | self.as_vec().serialize(serializer) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/schemars1.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | 3 | use crate::{Array, Slice, Vec}; 4 | use schemars1::{json_schema, JsonSchema, Schema, SchemaGenerator}; 5 | 6 | impl JsonSchema for Vec 7 | where 8 | T: JsonSchema, 9 | { 10 | fn schema_name() -> Cow<'static, str> { 11 | format!("NonEmpty_Array_of_{}", T::schema_name()).into() 12 | } 13 | 14 | fn json_schema(gen: &mut SchemaGenerator) -> Schema { 15 | json_schema!({ 16 | "type": "array", 17 | "items": gen.subschema_for::(), 18 | "minItems": 1, 19 | }) 20 | } 21 | } 22 | 23 | impl JsonSchema for Box> 24 | where 25 | T: JsonSchema, 26 | { 27 | fn schema_name() -> Cow<'static, str> { 28 | Vec::::schema_name() 29 | } 30 | 31 | fn json_schema(gen: &mut SchemaGenerator) -> Schema { 32 | Vec::::json_schema(gen) 33 | } 34 | } 35 | 36 | impl JsonSchema for Array 37 | where 38 | T: JsonSchema, 39 | { 40 | fn schema_name() -> Cow<'static, str> { 41 | format!("Array_of_{}_of_{}", N, T::schema_name()).into() 42 | } 43 | 44 | fn json_schema(gen: &mut SchemaGenerator) -> Schema { 45 | json_schema!({ 46 | "type": "array", 47 | "items": gen.subschema_for::(), 48 | "minItems": N, 49 | "maxItems": N, 50 | }) 51 | } 52 | } 53 | 54 | #[cfg(test)] 55 | mod tests { 56 | use super::*; 57 | use schemars1::schema_for; 58 | 59 | #[test] 60 | fn test_schema() { 61 | let schema = schema_for!(Vec); 62 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 63 | assert_eq!( 64 | serde_json::to_value(&schema).unwrap(), 65 | serde_json::json!({ 66 | "$schema": "https://json-schema.org/draft/2020-12/schema", 67 | "title": "NonEmpty_Array_of_int32", 68 | "type": "array", 69 | "items": { 70 | "type": "integer", 71 | "format": "int32" 72 | }, 73 | "minItems": 1 74 | }) 75 | ) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/schemars09.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | 3 | use crate::{Array, Slice, Vec}; 4 | use schemars09::{json_schema, JsonSchema, Schema, SchemaGenerator}; 5 | 6 | impl JsonSchema for Vec 7 | where 8 | T: JsonSchema, 9 | { 10 | fn schema_name() -> Cow<'static, str> { 11 | format!("NonEmpty_Array_of_{}", T::schema_name()).into() 12 | } 13 | 14 | fn json_schema(gen: &mut SchemaGenerator) -> Schema { 15 | json_schema!({ 16 | "type": "array", 17 | "items": gen.subschema_for::(), 18 | "minItems": 1, 19 | }) 20 | } 21 | } 22 | 23 | impl JsonSchema for Box> 24 | where 25 | T: JsonSchema, 26 | { 27 | fn schema_name() -> Cow<'static, str> { 28 | Vec::::schema_name() 29 | } 30 | 31 | fn json_schema(gen: &mut SchemaGenerator) -> Schema { 32 | Vec::::json_schema(gen) 33 | } 34 | } 35 | 36 | impl JsonSchema for Array 37 | where 38 | T: JsonSchema, 39 | { 40 | fn schema_name() -> Cow<'static, str> { 41 | format!("Array_of_{}_of_{}", N, T::schema_name()).into() 42 | } 43 | 44 | fn json_schema(gen: &mut SchemaGenerator) -> Schema { 45 | json_schema!({ 46 | "type": "array", 47 | "items": gen.subschema_for::(), 48 | "minItems": N, 49 | "maxItems": N, 50 | }) 51 | } 52 | } 53 | 54 | #[cfg(test)] 55 | mod tests { 56 | use super::*; 57 | use schemars09::schema_for; 58 | 59 | #[test] 60 | fn test_schema() { 61 | let schema = schema_for!(Vec); 62 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 63 | assert_eq!( 64 | serde_json::to_value(&schema).unwrap(), 65 | serde_json::json!({ 66 | "$schema": "https://json-schema.org/draft/2020-12/schema", 67 | "title": "NonEmpty_Array_of_int32", 68 | "type": "array", 69 | "items": { 70 | "type": "integer", 71 | "format": "int32" 72 | }, 73 | "minItems": 1 74 | }) 75 | ) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tests/try_from.rs: -------------------------------------------------------------------------------- 1 | //! See the documentation in `mirror_std/try_from.rs` for an explanation. 2 | 3 | #![allow(path_statements, clippy::no_effect)] 4 | 5 | // use std::{rc::Rc, sync::Arc}; 6 | 7 | use nunny::{Array, Slice, Vec}; 8 | 9 | const _: () = { 10 | fn _test<'a, T, const N: usize>() 11 | where 12 | T: 'a, 13 | { 14 | <&'a Array as TryFrom<&'a Slice>>::try_from; 15 | } 16 | }; 17 | 18 | const _: () = { 19 | fn _test<'a, T, const N: usize>() 20 | where 21 | T: 'a, 22 | { 23 | <&'a mut Array as TryFrom<&'a mut Slice>>::try_from; 24 | } 25 | }; 26 | 27 | // const _: () = { 28 | // fn _test() { 29 | // > as TryFrom>>>::try_from; 30 | // } 31 | // }; 32 | 33 | const _: () = { 34 | fn _test() { 35 | as TryFrom>>::try_from; 36 | } 37 | }; 38 | 39 | const _: () = { 40 | fn _test() 41 | where 42 | T: Copy, 43 | { 44 | as TryFrom<&Slice>>::try_from; 45 | } 46 | }; 47 | 48 | // const _: () = { 49 | // fn _test() 50 | // where 51 | // LaneCount: SupportedLaneCount, 52 | // T: SimdElement, 53 | // { 54 | // as TryFrom<&Slice>>::try_from; 55 | // } 56 | // }; 57 | 58 | const _: () = { 59 | fn _test() 60 | where 61 | T: Copy, 62 | { 63 | as TryFrom<&mut Slice>>::try_from; 64 | } 65 | }; 66 | 67 | // const _: () = { 68 | // fn _test() 69 | // where 70 | // LaneCount: SupportedLaneCount, 71 | // T: SimdElement, 72 | // { 73 | // as TryFrom<&mut Slice>>::try_from; 74 | // } 75 | // }; 76 | 77 | const _: () = { 78 | fn _test() { 79 | > as TryFrom>>>::try_from; 80 | } 81 | }; 82 | 83 | // const _: () = { 84 | // fn _test() { 85 | // > as TryFrom>>>::try_from; 86 | // } 87 | // }; 88 | 89 | const _: () = { 90 | fn _test() { 91 | > as TryFrom>>::try_from; 92 | } 93 | }; 94 | -------------------------------------------------------------------------------- /src/schemars08.rs: -------------------------------------------------------------------------------- 1 | use crate::{Array, Slice, Vec}; 2 | use schemars08::{ 3 | gen::SchemaGenerator, 4 | schema::{ArrayValidation, InstanceType, Schema, SchemaObject, SingleOrVec}, 5 | JsonSchema, 6 | }; 7 | 8 | impl JsonSchema for Vec 9 | where 10 | T: JsonSchema, 11 | { 12 | fn schema_name() -> String { 13 | format!("NonEmpty_Array_of_{}", T::schema_name()) 14 | } 15 | 16 | fn json_schema(gen: &mut SchemaGenerator) -> Schema { 17 | Schema::Object(SchemaObject { 18 | instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Array))), 19 | array: Some(Box::new(ArrayValidation { 20 | items: Some(SingleOrVec::Single(Box::new(gen.subschema_for::()))), 21 | min_items: Some(1), 22 | ..Default::default() 23 | })), 24 | ..Default::default() 25 | }) 26 | } 27 | } 28 | 29 | impl JsonSchema for Box> 30 | where 31 | T: JsonSchema, 32 | { 33 | fn schema_name() -> String { 34 | Vec::::schema_name() 35 | } 36 | 37 | fn json_schema(gen: &mut schemars08::gen::SchemaGenerator) -> Schema { 38 | Vec::::json_schema(gen) 39 | } 40 | } 41 | 42 | impl JsonSchema for Array 43 | where 44 | T: JsonSchema, 45 | { 46 | fn schema_name() -> String { 47 | format!("Array_of_{}_of_{}", N, T::schema_name()) 48 | } 49 | 50 | fn json_schema(gen: &mut schemars08::gen::SchemaGenerator) -> Schema { 51 | Schema::Object(SchemaObject { 52 | instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Array))), 53 | array: Some(Box::new(ArrayValidation { 54 | items: Some(SingleOrVec::Single(Box::new(gen.subschema_for::()))), 55 | min_items: Some(u32::try_from(N).unwrap_or(u32::MAX)), 56 | max_items: Some(u32::try_from(N).unwrap_or(u32::MAX)), 57 | ..Default::default() 58 | })), 59 | ..Default::default() 60 | }) 61 | } 62 | } 63 | 64 | #[cfg(test)] 65 | mod tests { 66 | use super::*; 67 | use schemars08::schema_for; 68 | 69 | #[test] 70 | fn test_schema() { 71 | let schema = schema_for!(Vec); 72 | println!("{}", serde_json::to_string_pretty(&schema).unwrap()); 73 | assert_eq!( 74 | serde_json::to_value(&schema).unwrap(), 75 | serde_json::json!({ 76 | "$schema": "http://json-schema.org/draft-07/schema#", 77 | "title": "NonEmpty_Array_of_int32", 78 | "type": "array", 79 | "items": { 80 | "type": "integer", 81 | "format": "int32" 82 | }, 83 | "minItems": 1 84 | }) 85 | ) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nunny" 3 | version = "0.2.2" 4 | edition = "2021" 5 | description = "the definitive non-empty slice/array/vec library for Rust" 6 | license = "MIT OR Apache-2.0" 7 | homepage = "https://crates.io/nunny" 8 | documentation = "https://docs.rs/nunny" 9 | repository = "https://github.com/aatifsyed/nunny" 10 | categories = [ 11 | "rust-patterns", 12 | "no-std", 13 | "memory-management", 14 | "embedded", 15 | "data-structures", 16 | ] 17 | 18 | [features] 19 | default = ["std"] 20 | std = ["alloc", "serde1/std"] 21 | alloc = ["serde1?/alloc"] 22 | # This feature will always track the latest (API) version of serde. 23 | # Changing it to `serde2` is not considered a breaking change 24 | serde = ["serde1"] 25 | serde1 = ["dep:serde1"] 26 | # This feature will always track the latest (API) version of arbitrary. 27 | # Changing it to `arbitrary2` is not considered a breaking change 28 | arbitrary = ["arbitrary1"] 29 | arbitrary1 = ["dep:arbitrary1", "std"] 30 | # This feature will always track the latest (API) version of quickcheck. 31 | # Changing it to `quickcheck2` is not considered a breaking change 32 | quickcheck = ["quickcheck1"] 33 | quickcheck1 = ["dep:quickcheck1", "std"] 34 | # This feature will always track the latest (API) version of proptest. 35 | # Changing it to `proptest2` is not considered a breaking change 36 | # proptest has a `std` and `alloc` feature, but trying --no-default-features with them broke... 37 | proptest = ["proptest1"] 38 | proptest1 = ["dep:proptest1", "std"] 39 | # This feature will always track the latest (API) version of schemars. 40 | # Changing it to a different major version `schemars09` is not considered a breaking change 41 | schemars = ["schemars1"] 42 | schemars08 = ["dep:schemars08", "std"] 43 | schemars09 = ["dep:schemars09", "std"] 44 | schemars1 = ["dep:schemars1", "std"] 45 | 46 | [dependencies] 47 | proptest1 = { version = "1.4.0", package = "proptest", optional = true } 48 | arbitrary1 = { version = "1.3.2", package = "arbitrary", optional = true } 49 | quickcheck1 = { version = "1.0.3", package = "quickcheck", optional = true, default-features = false } 50 | serde1 = { version = "1.0.198", package = "serde", optional = true, default-features = false } 51 | schemars08 = { version = "0.8", package = "schemars", optional = true, default-features = false } 52 | schemars09 = { version = "0.9", package = "schemars", optional = true, default-features = false } 53 | schemars1 = { version = "1", package = "schemars", optional = true, default-features = false } 54 | 55 | [workspace] 56 | members = ["gen"] 57 | 58 | [dev-dependencies] 59 | divan = { git = "https://github.com/OliverKillane/divan", branch = "enh/file-output" } # json output 60 | nonempty = "0.11" 61 | serde_json = "1" 62 | 63 | [[bench]] 64 | name = "against-nonempty" 65 | harness = false 66 | 67 | [package.metadata.docs.rs] 68 | all-features = true 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | The definitive non-empty slice/array/vec library for Rust. 4 | 5 | # Features 6 | Nonempty-by-construction API 7 | ```rust 8 | let mut my_vec = NonEmpty::>::of("hello"); // construct once 9 | my_vec.push("world"); // continue using your normal APIs 10 | let hello: &str = my_vec.first(); // preserve the guarantee that there is at least one element 11 | ``` 12 | 13 | `#[repr(transparent)]` allows advanced usecases and guarantees optimum performance[^1]: 14 | ```rust 15 | let src = &mut ["hello", "world"]; 16 | let ne = NonEmpty::<[_]>::new_mut(src).unwrap(); 17 | // ^ uses the same backing memory 18 | let world: &str = ne.last(); 19 | ``` 20 | 21 | Total API coverage. 22 | For every impl of [`From`], [`TryFrom`], [`PartialEq`] and [`PartialOrd`] in [`std`][^2], 23 | there is a corresponding impl in this library for [`Slice`], [`Array`] and [`Vec`]. 24 | _This includes more exotic types_: 25 | ```rust 26 | let nun: Box> = vec![0xDEAD, 0xBEEF].into(); 27 | let cow: Cow> = (&*nun).into(); 28 | let arc: Arc> = cow.into_owned().into(); 29 | ``` 30 | 31 | `const`-friendly API. Where possible, all methods are `const`. 32 | ```rust 33 | const TWO: &NonEmpty<[&str]> = slice!["together", "forever"]; 34 | const FIRST: &str = TWO.first(); 35 | const ONE: &NonEmpty<[&str]> = NonEmpty::<[_]>::of(&"lonely"); 36 | ``` 37 | 38 | Extensive feature gating supporting: 39 | - `no-std` environments with no allocator. 40 | - `alloc`-enabled environments. 41 | - full-`std`-enabled environments. 42 | - interaction with crates like `serde` and `arbitrary`. 43 | 44 | Iterator support: 45 | Specialized [`Iterator`] methods remove branches to handle empty iterators, 46 | _and_ preserve invariants even when chaining combinators. 47 | ```rust 48 | let v = vec![1, 2, 3]; 49 | let _: Option<&u8> = v.iter().last(); 50 | // ^ normally you have to handle the empty case 51 | let _: &u8 = v.iter_ne().last(); 52 | // ^ but we know there is at least one element 53 | let _: u8 = v.iter_ne().copied().last(); 54 | // ^ using this combinator preserves the invariant 55 | ``` 56 | 57 | Thoughtful design: 58 | - [`NonZeroUsize`] is inserted [where](Slice::len) [appropriate](Vec::truncate). 59 | - Everything [`Deref`](core::ops::Deref)/[`DerefMut`](core::ops::DerefMut)s 60 | down to a [`NonEmpty>`], which in turn `deref/mut`s down to a `[T]`. 61 | - Liberal applications of [`cmp`](core::cmp), [`borrow`](core::borrow), [`convert`](core::convert) 62 | traits. 63 | If there's a missing API that you'd like, please raise an issue! 64 | 65 | [^1]: Other crates like [`nonempty`](https://docs.rs/nonempty/latest/nonempty/struct.NonEmpty.html) 66 | require an indirection. 67 | [^2]: Barring impls on `!#[fundamental]` types like [`Arc`](std::sync::Arc). 68 | Fun fact: our tests were generated from [`std`]'s rustdoc! 69 | 70 | 71 | -------------------------------------------------------------------------------- /benches/against-nonempty.rs: -------------------------------------------------------------------------------- 1 | use std::hint::black_box; 2 | 3 | use divan::Bencher; 4 | 5 | const LENS: &[usize] = &[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]; 6 | 7 | #[divan::bench(types = [Ours, Theirs, Ours, Theirs], args = LENS)] 8 | fn clone(bencher: Bencher, len: usize) 9 | where 10 | B::Subject: Clone, 11 | { 12 | let bench_me = black_box(B::setup(len)); 13 | bencher.bench_local(move || B::run_clone(&bench_me)); 14 | } 15 | 16 | #[divan::bench(types = [Ours, Theirs, Ours, Theirs], args = LENS)] 17 | fn into_iter(bencher: Bencher, len: usize) 18 | where 19 | B::Subject: Clone + IntoIterator, 20 | { 21 | let bench_me = black_box(B::setup(len)); 22 | bencher.bench_local(move || B::run_into_iter(&bench_me)); 23 | } 24 | #[divan::bench(types = [Ours, Theirs, Ours, Theirs], args = LENS)] 25 | fn iter(bencher: Bencher, len: usize) 26 | where 27 | for<'a> &'a B::Subject: IntoIterator, 28 | { 29 | let bench_me = black_box(B::setup(len)); 30 | bencher.bench_local(move || B::run_iter(&bench_me)); 31 | } 32 | #[divan::bench(types = [Ours, Theirs, Ours, Theirs], args = LENS)] 33 | fn partial_eq(bencher: Bencher, len: usize) 34 | where 35 | B::Subject: PartialEq, 36 | { 37 | let left = black_box(B::setup(len)); 38 | let right = black_box(B::setup(len)); 39 | bencher.bench_local(move || B::run_partial_eq(&left, &right)); 40 | } 41 | 42 | struct Ours(std::marker::PhantomData T>); 43 | struct Theirs(std::marker::PhantomData T>); 44 | trait BenchMe { 45 | type Subject; 46 | fn setup(len: usize) -> Self::Subject; 47 | fn run_clone(subject: &Self::Subject) 48 | where 49 | Self::Subject: Clone, 50 | { 51 | black_box(subject.clone()); 52 | } 53 | fn run_into_iter(subject: &Self::Subject) 54 | where 55 | Self::Subject: IntoIterator + Clone, 56 | { 57 | for it in black_box(subject.clone()) { 58 | black_box(it); 59 | } 60 | } 61 | fn run_iter(subject: &Self::Subject) 62 | where 63 | for<'a> &'a Self::Subject: IntoIterator, 64 | { 65 | for it in black_box(subject) { 66 | black_box(it); 67 | } 68 | } 69 | fn run_partial_eq(left: &Self::Subject, right: &Self::Subject) 70 | where 71 | Self::Subject: PartialEq, 72 | { 73 | black_box(black_box(left) == black_box(right)); 74 | } 75 | } 76 | 77 | impl BenchMe for Ours 78 | where 79 | T: Default, 80 | { 81 | type Subject = nunny::Vec; 82 | 83 | fn setup(len: usize) -> Self::Subject { 84 | let mut src = Vec::new(); 85 | src.resize_with(len, Default::default); 86 | black_box(match nunny::Vec::new(src) { 87 | Ok(it) => it, 88 | Err(_) => panic!(), 89 | }) 90 | } 91 | } 92 | impl BenchMe for Theirs 93 | where 94 | T: Default, 95 | { 96 | type Subject = nonempty::NonEmpty; 97 | 98 | fn setup(len: usize) -> Self::Subject { 99 | let mut src = Vec::new(); 100 | src.resize_with(len, Default::default); 101 | black_box(nonempty::NonEmpty::from_vec(src).unwrap()) 102 | } 103 | } 104 | 105 | fn main() { 106 | divan::main() 107 | } 108 | -------------------------------------------------------------------------------- /tests/partial_eq.rs: -------------------------------------------------------------------------------- 1 | #![allow(path_statements, clippy::no_effect)] 2 | 3 | use std::{borrow::Cow, collections::VecDeque}; 4 | 5 | use nunny::{Array, Slice, Vec}; 6 | 7 | const _: () = { 8 | fn _test() 9 | where 10 | A: PartialEq, 11 | { 12 | as PartialEq>>::eq; 13 | } 14 | }; 15 | 16 | const _: () = { 17 | fn _test() 18 | where 19 | A: PartialEq, 20 | { 21 | as PartialEq<&Slice>>::eq; 22 | } 23 | }; 24 | 25 | const _: () = { 26 | fn _test() 27 | where 28 | A: PartialEq, 29 | { 30 | as PartialEq<&mut Slice>>::eq; 31 | } 32 | }; 33 | 34 | const _: () = { 35 | fn _test() 36 | where 37 | B: PartialEq, 38 | { 39 | <&Slice as PartialEq>>::eq; 40 | } 41 | }; 42 | 43 | const _: () = { 44 | fn _test() 45 | where 46 | B: PartialEq, 47 | { 48 | <&mut Slice as PartialEq>>::eq; 49 | } 50 | }; 51 | 52 | const _: () = { 53 | fn _test() 54 | where 55 | B: PartialEq, 56 | { 57 | as PartialEq>>::eq; 58 | } 59 | }; 60 | 61 | const _: () = { 62 | fn _test() 63 | where 64 | A: PartialEq, 65 | { 66 | as PartialEq>>::eq; 67 | } 68 | }; 69 | 70 | const _: () = { 71 | fn _test() 72 | where 73 | A: PartialEq, 74 | { 75 | as PartialEq>>::eq; 76 | } 77 | }; 78 | 79 | const _: () = { 80 | fn _test() 81 | where 82 | T: PartialEq + Clone, 83 | { 84 | > as PartialEq<&Slice>>::eq; 85 | } 86 | }; 87 | 88 | const _: () = { 89 | fn _test() 90 | where 91 | T: PartialEq + Clone, 92 | { 93 | > as PartialEq<&mut Slice>>::eq; 94 | } 95 | }; 96 | 97 | const _: () = { 98 | fn _test() 99 | where 100 | T: PartialEq, 101 | { 102 | as PartialEq<&Slice>>::eq; 103 | } 104 | }; 105 | 106 | const _: () = { 107 | fn _test() 108 | where 109 | T: PartialEq, 110 | { 111 | as PartialEq<&Slice>>::eq; 112 | } 113 | }; 114 | 115 | const _: () = { 116 | fn _test() 117 | where 118 | T: PartialEq, 119 | { 120 | as PartialEq<&mut Slice>>::eq; 121 | } 122 | }; 123 | 124 | const _: () = { 125 | fn _test() 126 | where 127 | T: PartialEq, 128 | { 129 | as PartialEq<&mut Slice>>::eq; 130 | } 131 | }; 132 | 133 | const _: () = { 134 | fn _test() 135 | where 136 | T: PartialEq, 137 | { 138 | as PartialEq>>::eq; 139 | } 140 | }; 141 | 142 | const _: () = { 143 | fn _test() 144 | where 145 | T: PartialEq, 146 | { 147 | <&Slice as PartialEq>>::eq; 148 | } 149 | }; 150 | 151 | const _: () = { 152 | fn _test() 153 | where 154 | T: PartialEq, 155 | { 156 | <&mut Slice as PartialEq>>::eq; 157 | } 158 | }; 159 | 160 | const _: () = { 161 | fn _test() 162 | where 163 | T: PartialEq + Clone, 164 | { 165 | > as PartialEq>>::eq; 166 | } 167 | }; 168 | 169 | const _: () = { 170 | fn _test() 171 | where 172 | T: PartialEq, 173 | { 174 | as PartialEq>>::eq; 175 | } 176 | }; 177 | 178 | const _: () = { 179 | fn _test() 180 | where 181 | T: PartialEq, 182 | { 183 | as PartialEq<&Array>>::eq; 184 | } 185 | }; 186 | 187 | const _: () = { 188 | fn _test() 189 | where 190 | T: PartialEq, 191 | { 192 | as PartialEq<&Array>>::eq; 193 | } 194 | }; 195 | 196 | const _: () = { 197 | fn _test() 198 | where 199 | T: PartialEq, 200 | { 201 | as PartialEq<&mut Array>>::eq; 202 | } 203 | }; 204 | 205 | const _: () = { 206 | fn _test() 207 | where 208 | T: PartialEq, 209 | { 210 | as PartialEq>>::eq; 211 | } 212 | }; 213 | 214 | const _: () = { 215 | fn _test() 216 | where 217 | T: PartialEq, 218 | { 219 | as PartialEq>>::eq; 220 | } 221 | }; 222 | -------------------------------------------------------------------------------- /src/mirror_std/try_from.rs: -------------------------------------------------------------------------------- 1 | //! There should be an `impl` here that corresponds to every [`TryFrom`] 2 | //! implementation in [`std`] between: 3 | //! - `[T; N]` 4 | //! - `[T]` 5 | //! - [`Vec`](alloc::vec::Vec) 6 | //! 7 | //! Here's the methodology: 8 | //! - Use the `gen` tool in this repository to scrape rustdoc 9 | //! (HTML, not JSON - it's much easier) 10 | //! - Output the `test/try_from.rs` file in this repository. 11 | //! This is effectively a description of the standard library conversions. 12 | //! - Redact unstable items, and conversions we can't implement because we're 13 | //! not std. 14 | //! - Switch the types from the standard library to our libraries. 15 | //! - Write implementations _in the same order_ in this file. 16 | 17 | #[cfg(feature = "alloc")] 18 | use crate::Vec; 19 | use crate::{Array, Slice, TryFromSliceError}; 20 | #[cfg(feature = "alloc")] 21 | use alloc::boxed::Box; 22 | // use alloc::{rc::Rc, sync::Arc}; 23 | 24 | impl<'a, T, const N: usize> TryFrom<&'a Slice> for &'a Array { 25 | type Error = TryFromSliceError; 26 | 27 | fn try_from(value: &'a Slice) -> Result { 28 | value 29 | .as_slice() 30 | .try_into() 31 | .ok() 32 | .and_then(Array::new_ref) 33 | .ok_or(TryFromSliceError(())) 34 | } 35 | } 36 | 37 | impl<'a, T, const N: usize> TryFrom<&'a mut Slice> for &'a mut Array { 38 | type Error = TryFromSliceError; 39 | 40 | fn try_from(value: &'a mut Slice) -> Result { 41 | value 42 | .as_mut_slice() 43 | .try_into() 44 | .ok() 45 | .and_then(Array::new_mut) 46 | .ok_or(TryFromSliceError(())) 47 | } 48 | } 49 | 50 | // impl TryFrom>> for Arc> { 51 | // type Error = (); 52 | 53 | // fn try_from(value: Arc>) -> Result { 54 | // todo!() 55 | // } 56 | // } 57 | 58 | #[cfg(feature = "alloc")] 59 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 60 | impl TryFrom> for Array { 61 | type Error = Vec; 62 | 63 | fn try_from(value: Vec) -> Result { 64 | // Safety: 65 | // - already non-empty by construction 66 | match value.into_vec().try_into() { 67 | Ok(it) => Ok(unsafe { Array::new_unchecked(it) }), 68 | Err(it) => Err(unsafe { Vec::new_unchecked(it) }), 69 | } 70 | } 71 | } 72 | 73 | impl TryFrom<&Slice> for Array 74 | where 75 | T: Copy, 76 | { 77 | type Error = TryFromSliceError; 78 | 79 | fn try_from(value: &Slice) -> Result { 80 | // Safety: 81 | // - already non-empty by construction 82 | match value.as_slice().try_into() { 83 | Ok(it) => Ok(unsafe { Array::new_unchecked(it) }), 84 | Err(_) => Err(TryFromSliceError(())), 85 | } 86 | } 87 | } 88 | impl TryFrom<&mut Slice> for Array 89 | where 90 | T: Copy, 91 | { 92 | type Error = TryFromSliceError; 93 | 94 | fn try_from(value: &mut Slice) -> Result { 95 | // Safety: 96 | // - already non-empty by construction 97 | match value.as_mut_slice().try_into() { 98 | Ok(it) => Ok(unsafe { Array::new_unchecked(it) }), 99 | Err(_) => Err(TryFromSliceError(())), 100 | } 101 | } 102 | } 103 | 104 | #[cfg(feature = "alloc")] 105 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 106 | impl TryFrom>> for Box> { 107 | type Error = Box>; 108 | 109 | fn try_from(value: Box>) -> Result { 110 | // Safety: 111 | // - already checked len 112 | match value.len_ne().get() == N { 113 | true => Ok(unsafe { boxed_slice_as_array_unchecked(value) }), 114 | false => Err(value), 115 | } 116 | } 117 | } 118 | 119 | // impl TryFrom>> for Rc> { 120 | // type Error = (); 121 | 122 | // fn try_from(value: Rc>) -> Result { 123 | // todo!() 124 | // } 125 | // } 126 | 127 | #[cfg(feature = "alloc")] 128 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 129 | impl TryFrom> for Box> { 130 | type Error = Vec; 131 | 132 | fn try_from(value: Vec) -> Result { 133 | // Safety: 134 | // - already checked len 135 | match value.len() == N { 136 | true => Ok(unsafe { boxed_slice_as_array_unchecked(value.into_boxed_slice()) }), 137 | false => Err(value), 138 | } 139 | } 140 | } 141 | 142 | /// Casts a boxed slice to a boxed array. 143 | /// 144 | /// # Safety 145 | /// 146 | /// `boxed_slice.len()` must be exactly `N`. 147 | #[cfg(feature = "alloc")] 148 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 149 | unsafe fn boxed_slice_as_array_unchecked( 150 | boxed_slice: Box>, 151 | ) -> Box> { 152 | debug_assert_eq!(boxed_slice.len(), N); 153 | 154 | let ptr = Box::into_raw(boxed_slice); 155 | unsafe { Box::from_raw(ptr as *mut Array) } 156 | } 157 | -------------------------------------------------------------------------------- /src/mirror_std/partial_eq.rs: -------------------------------------------------------------------------------- 1 | //! There should be an `impl` here that corresponds to every [`PartialEq`] 2 | //! implementation in [`std`] between: 3 | //! - `[T; N]` 4 | //! - `[T]` 5 | //! - [`Vec`](alloc::vec::Vec) 6 | //! 7 | //! Here's the methodology: 8 | //! - Use the `gen` tool in this repository to scrape rustdoc 9 | //! (HTML, not JSON - it's much easier) 10 | //! - Output the `test/try_from.rs` file in this repository. 11 | //! This is effectively a description of the standard library conversions. 12 | //! - Redact unstable items, and implementations we can't do because we're not std. 13 | //! - Switch the types from the standard library to our libraries. 14 | //! - Write implementations _in the same order_ in this file. 15 | 16 | #[cfg(feature = "alloc")] 17 | use crate::Vec; 18 | use crate::{Array, Slice}; 19 | #[cfg(feature = "alloc")] 20 | use alloc::{borrow::Cow, collections::VecDeque}; 21 | 22 | impl PartialEq> for Slice 23 | where 24 | A: PartialEq, 25 | { 26 | fn eq(&self, other: &Slice) -> bool { 27 | <[_] as PartialEq<[_]>>::eq(self, other) 28 | } 29 | } 30 | 31 | impl PartialEq<&Slice> for Array 32 | where 33 | A: PartialEq, 34 | { 35 | fn eq(&self, other: &&Slice) -> bool { 36 | <[_] as PartialEq<[_]>>::eq(self, other) 37 | } 38 | } 39 | 40 | impl PartialEq<&mut Slice> for Array 41 | where 42 | A: PartialEq, 43 | { 44 | fn eq(&self, other: &&mut Slice) -> bool { 45 | <[_] as PartialEq<[_]>>::eq(self, other) 46 | } 47 | } 48 | 49 | impl PartialEq> for &Slice 50 | where 51 | B: PartialEq, 52 | { 53 | fn eq(&self, other: &Array) -> bool { 54 | <[_] as PartialEq<[_]>>::eq(self, other) 55 | } 56 | } 57 | 58 | impl PartialEq> for &mut Slice 59 | where 60 | B: PartialEq, 61 | { 62 | fn eq(&self, other: &Array) -> bool { 63 | <[_] as PartialEq<[_]>>::eq(self, other) 64 | } 65 | } 66 | 67 | impl PartialEq> for Slice 68 | where 69 | B: PartialEq, 70 | { 71 | fn eq(&self, other: &Array) -> bool { 72 | <[_] as PartialEq<[_]>>::eq(self, other) 73 | } 74 | } 75 | 76 | impl PartialEq> for Array 77 | where 78 | A: PartialEq, 79 | { 80 | fn eq(&self, other: &Array) -> bool { 81 | <[_] as PartialEq<[_]>>::eq(self, other) 82 | } 83 | } 84 | 85 | impl PartialEq> for Array 86 | where 87 | A: PartialEq, 88 | { 89 | fn eq(&self, other: &Slice) -> bool { 90 | <[_] as PartialEq<[_]>>::eq(self, other) 91 | } 92 | } 93 | 94 | #[cfg(feature = "alloc")] 95 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 96 | impl PartialEq<&Slice> for Cow<'_, Slice> 97 | where 98 | T: PartialEq + Clone, 99 | { 100 | fn eq(&self, other: &&Slice) -> bool { 101 | <[_] as PartialEq<[_]>>::eq(self, other) 102 | } 103 | } 104 | 105 | #[cfg(feature = "alloc")] 106 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 107 | impl PartialEq<&mut Slice> for Cow<'_, Slice> 108 | where 109 | T: PartialEq + Clone, 110 | { 111 | fn eq(&self, other: &&mut Slice) -> bool { 112 | <[_] as PartialEq<[_]>>::eq(self, other) 113 | } 114 | } 115 | 116 | #[cfg(feature = "alloc")] 117 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 118 | impl PartialEq<&Slice> for VecDeque 119 | where 120 | T: PartialEq, 121 | { 122 | fn eq(&self, other: &&Slice) -> bool { 123 | if self.len() != other.len_ne().get() { 124 | return false; 125 | } 126 | let (sa, sb) = self.as_slices(); 127 | let (oa, ob) = other[..].split_at(sa.len()); 128 | sa == oa && sb == ob 129 | } 130 | } 131 | 132 | #[cfg(feature = "alloc")] 133 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 134 | impl PartialEq<&Slice> for Vec 135 | where 136 | T: PartialEq, 137 | { 138 | fn eq(&self, other: &&Slice) -> bool { 139 | <[_] as PartialEq<[_]>>::eq(self, other) 140 | } 141 | } 142 | 143 | #[cfg(feature = "alloc")] 144 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 145 | impl PartialEq<&mut Slice> for VecDeque 146 | where 147 | T: PartialEq, 148 | { 149 | fn eq(&self, other: &&mut Slice) -> bool { 150 | PartialEq::<&Slice>::eq(self, &&**other) 151 | } 152 | } 153 | 154 | #[cfg(feature = "alloc")] 155 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 156 | impl PartialEq<&mut Slice> for Vec 157 | where 158 | T: PartialEq, 159 | { 160 | fn eq(&self, other: &&mut Slice) -> bool { 161 | <[_] as PartialEq<[_]>>::eq(self, other) 162 | } 163 | } 164 | 165 | #[cfg(feature = "alloc")] 166 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 167 | impl PartialEq> for Vec 168 | where 169 | T: PartialEq, 170 | { 171 | fn eq(&self, other: &Slice) -> bool { 172 | <[_] as PartialEq<[_]>>::eq(self, other) 173 | } 174 | } 175 | 176 | #[cfg(feature = "alloc")] 177 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 178 | impl PartialEq> for &Slice 179 | where 180 | T: PartialEq, 181 | { 182 | fn eq(&self, other: &Vec) -> bool { 183 | <[_] as PartialEq<[_]>>::eq(self, other) 184 | } 185 | } 186 | 187 | #[cfg(feature = "alloc")] 188 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 189 | impl PartialEq> for &mut Slice 190 | where 191 | T: PartialEq, 192 | { 193 | fn eq(&self, other: &Vec) -> bool { 194 | <[_] as PartialEq<[_]>>::eq(self, other) 195 | } 196 | } 197 | 198 | #[cfg(feature = "alloc")] 199 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 200 | impl PartialEq> for Cow<'_, Slice> 201 | where 202 | T: PartialEq + Clone, 203 | { 204 | fn eq(&self, other: &Vec) -> bool { 205 | <[_] as PartialEq<[_]>>::eq(self, other) 206 | } 207 | } 208 | 209 | #[cfg(feature = "alloc")] 210 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 211 | impl PartialEq> for Slice 212 | where 213 | T: PartialEq, 214 | { 215 | fn eq(&self, other: &Vec) -> bool { 216 | <[_] as PartialEq<[_]>>::eq(self, other) 217 | } 218 | } 219 | 220 | #[cfg(feature = "alloc")] 221 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 222 | impl PartialEq<&Array> for VecDeque 223 | where 224 | T: PartialEq, 225 | { 226 | fn eq(&self, other: &&Array) -> bool { 227 | PartialEq::<&Slice>::eq(self, &&***other) 228 | } 229 | } 230 | 231 | #[cfg(feature = "alloc")] 232 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 233 | impl PartialEq<&Array> for Vec 234 | where 235 | T: PartialEq, 236 | { 237 | fn eq(&self, other: &&Array) -> bool { 238 | <[_] as PartialEq<[_]>>::eq(self, other) 239 | } 240 | } 241 | 242 | #[cfg(feature = "alloc")] 243 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 244 | impl PartialEq<&mut Array> for VecDeque 245 | where 246 | T: PartialEq, 247 | { 248 | fn eq(&self, other: &&mut Array) -> bool { 249 | PartialEq::<&Slice>::eq(self, &&***other) 250 | } 251 | } 252 | 253 | #[cfg(feature = "alloc")] 254 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 255 | impl PartialEq> for VecDeque 256 | where 257 | T: PartialEq, 258 | { 259 | fn eq(&self, other: &Array) -> bool { 260 | PartialEq::<&Slice>::eq(self, &&**other) 261 | } 262 | } 263 | 264 | #[cfg(feature = "alloc")] 265 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 266 | impl PartialEq> for Vec 267 | where 268 | T: PartialEq, 269 | { 270 | fn eq(&self, other: &Array) -> bool { 271 | <[_] as PartialEq<[_]>>::eq(self, other) 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /gen/src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::{Parser, ValueEnum}; 2 | use owo_colors::OwoColorize as _; 3 | use proc_macro2::TokenStream; 4 | use quote::{quote, ToTokens}; 5 | use scraper::{Html, Selector}; 6 | use syn::{ 7 | parse::{Parse, ParseStream, Parser as _}, 8 | punctuated::Punctuated, 9 | visit_mut::{self, VisitMut}, 10 | Generics, Ident, Lifetime, Path, Token, Type, TypePath, 11 | }; 12 | 13 | #[derive(Parser)] 14 | struct Args { 15 | #[arg( 16 | long, 17 | default_value = "https://doc.rust-lang.org/1.77.2/std/convert/trait.From.html" 18 | )] 19 | url: String, 20 | #[arg(long, default_value = "section.impl > .code-header")] 21 | selector: String, 22 | #[arg(long, default_value = "from")] 23 | method: String, 24 | #[arg(long, default_value = "test")] 25 | out: Out, 26 | } 27 | 28 | fn main() -> anyhow::Result<()> { 29 | let Args { 30 | url, 31 | selector, 32 | method, 33 | out, 34 | } = Args::parse(); 35 | let method = Ident::parse.parse_str(&method)?; 36 | let html = ureq::get(&url).call()?.into_string()?; 37 | let html = Html::parse_document(&html); 38 | for selected in 39 | html.select(&Selector::parse(&selector).map_err(|it| anyhow::Error::msg(it.to_string()))?) 40 | { 41 | let text = selected.text().collect::>().join(" "); 42 | eprintln!("{}", text.dimmed()); 43 | 44 | match syn::parse_str::(&text).map(|it| select(it, &method, out)) { 45 | Ok(Some(it)) => { 46 | let rendered = prettyplease::unparse(&syn::File { 47 | shebang: None, 48 | attrs: vec![], 49 | items: vec![syn::parse_quote! { 50 | #it 51 | }], 52 | }); 53 | println!("{}", rendered.green()) 54 | } 55 | Ok(None) => eprintln!("{}", "skip".yellow()), 56 | Err(e) => { 57 | let e = syn_miette::Error::new(e, text).render(); 58 | eprintln!("{}", e.red()); 59 | } 60 | } 61 | } 62 | Ok(()) 63 | } 64 | 65 | #[derive(ValueEnum, Clone, Copy)] 66 | enum Out { 67 | Test, 68 | Impl, 69 | } 70 | 71 | /// Change the types: 72 | /// - [T] -> Slice 73 | /// - [T; N] -> Array 74 | /// 75 | /// Select `impls` with any of the following types: 76 | /// - Slice 77 | /// - Array 78 | /// - Vec 79 | /// 80 | /// Select impls which fill the following: 81 | /// - impl _<$src> for $dst 82 | /// 83 | /// 84 | fn select(mut impl_: Impl, method: &Ident, out: Out) -> Option { 85 | struct Visitor { 86 | include: bool, 87 | } 88 | impl VisitMut for Visitor { 89 | fn visit_type_mut(&mut self, outer: &mut syn::Type) { 90 | match outer { 91 | Type::Array(inner) => { 92 | visit_mut::visit_type_array_mut(self, inner); 93 | let len = &inner.len; 94 | let elem = &inner.elem; 95 | *outer = syn::parse_quote! { 96 | Array<#len, #elem> 97 | }; 98 | self.include = true; 99 | } 100 | Type::BareFn(inner) => visit_mut::visit_type_bare_fn_mut(self, inner), 101 | Type::Group(inner) => visit_mut::visit_type_group_mut(self, inner), 102 | Type::ImplTrait(inner) => visit_mut::visit_type_impl_trait_mut(self, inner), 103 | Type::Infer(inner) => visit_mut::visit_type_infer_mut(self, inner), 104 | Type::Macro(inner) => visit_mut::visit_type_macro_mut(self, inner), 105 | Type::Never(inner) => visit_mut::visit_type_never_mut(self, inner), 106 | Type::Paren(inner) => visit_mut::visit_type_paren_mut(self, inner), 107 | Type::Path(inner) => { 108 | visit_mut::visit_type_path_mut(self, inner); 109 | if inner.path.is_ident("Vec") { 110 | self.include = true; 111 | } 112 | } 113 | Type::Ptr(inner) => visit_mut::visit_type_ptr_mut(self, inner), 114 | Type::Reference(inner) => visit_mut::visit_type_reference_mut(self, inner), 115 | Type::Slice(inner) => { 116 | visit_mut::visit_type_slice_mut(self, inner); 117 | let elem = &inner.elem; 118 | *outer = syn::parse_quote! { 119 | Slice<#elem> 120 | }; 121 | self.include = true; 122 | } 123 | Type::TraitObject(inner) => visit_mut::visit_type_trait_object_mut(self, inner), 124 | Type::Tuple(inner) => visit_mut::visit_type_tuple_mut(self, inner), 125 | Type::Verbatim(_) => {} 126 | other => todo!("{:?}", other), 127 | } 128 | } 129 | } 130 | 131 | let mut visitor = Visitor { include: false }; 132 | 133 | let Impl { 134 | impl_token: _, 135 | generics, 136 | trait_, 137 | for_token: _, 138 | ty, 139 | } = &mut impl_; 140 | 141 | visitor.visit_generics_mut(generics); 142 | visitor.visit_path_mut(trait_); 143 | visitor.visit_type_mut(ty); 144 | 145 | if !visitor.include { 146 | return None; 147 | } 148 | 149 | let Impl { 150 | impl_token: _, 151 | generics: 152 | Generics { 153 | lt_token, 154 | params, 155 | gt_token, 156 | where_clause, 157 | }, 158 | trait_, 159 | for_token: _, 160 | ty: dst, 161 | } = &impl_; 162 | 163 | let src = trait_.segments.last().and_then(|it| match &it.arguments { 164 | syn::PathArguments::None => None, 165 | syn::PathArguments::AngleBracketed(it) => { 166 | let args = it.args.iter().collect::>(); 167 | match args.as_slice() { 168 | [syn::GenericArgument::Type(it)] => Some(it), 169 | _ => None, 170 | } 171 | } 172 | syn::PathArguments::Parenthesized(_) => None, 173 | })?; 174 | 175 | let trait_ = trait_ 176 | .segments 177 | .iter() 178 | .map(|it| &it.ident) 179 | .collect::>(); 180 | 181 | let ret = match out { 182 | Out::Test => quote! { 183 | const _: () = { 184 | fn _test 185 | #lt_token 186 | #params 187 | #gt_token 188 | () 189 | #where_clause 190 | { 191 | <#dst as #trait_<#src>>::#method; 192 | } 193 | } 194 | }, 195 | Out::Impl => quote! { 196 | impl #lt_token #params #gt_token 197 | #trait_<#src> 198 | for #dst 199 | #where_clause 200 | { 201 | fn #method(&self, other: &#src) {} 202 | } 203 | }, 204 | }; 205 | 206 | Some(ret) 207 | } 208 | 209 | #[derive(Debug)] 210 | struct Impl { 211 | pub impl_token: Token![impl], 212 | pub generics: Generics, 213 | pub trait_: Path, 214 | pub for_token: Token![for], 215 | pub ty: Type, 216 | } 217 | 218 | impl ToTokens for Impl { 219 | fn to_tokens(&self, tokens: &mut TokenStream) { 220 | let Self { 221 | impl_token, 222 | generics: 223 | Generics { 224 | lt_token, 225 | params, 226 | gt_token, 227 | where_clause, 228 | }, 229 | trait_, 230 | for_token, 231 | ty, 232 | } = self; 233 | impl_token.to_tokens(tokens); 234 | lt_token.to_tokens(tokens); 235 | params.to_tokens(tokens); 236 | gt_token.to_tokens(tokens); 237 | trait_.to_tokens(tokens); 238 | for_token.to_tokens(tokens); 239 | ty.to_tokens(tokens); 240 | where_clause.to_tokens(tokens); 241 | } 242 | } 243 | 244 | impl Parse for Impl { 245 | // Hacked together from `Parse for syn::ItemImpl` 246 | fn parse(input: ParseStream) -> syn::Result { 247 | let impl_token = input.parse()?; 248 | 249 | let has_generics = input.peek(Token![<]) 250 | && (input.peek2(Token![>]) 251 | || input.peek2(Token![#]) 252 | || (input.peek2(Ident) || input.peek2(Lifetime)) 253 | && (input.peek3(Token![:]) 254 | || input.peek3(Token![,]) 255 | || input.peek3(Token![>]) 256 | || input.peek3(Token![=])) 257 | || input.peek2(Token![const])); 258 | let mut generics: Generics = if has_generics { 259 | input.parse()? 260 | } else { 261 | Generics::default() 262 | }; 263 | 264 | let mut first_ty: Type = input.parse()?; 265 | let trait_; 266 | 267 | let for_token: Token![for] = input.parse()?; 268 | let mut first_ty_ref = &first_ty; 269 | while let Type::Group(ty) = first_ty_ref { 270 | first_ty_ref = &ty.elem; 271 | } 272 | if let Type::Path(TypePath { qself: None, .. }) = first_ty_ref { 273 | while let Type::Group(ty) = first_ty { 274 | first_ty = *ty.elem; 275 | } 276 | if let Type::Path(TypePath { qself: None, path }) = first_ty { 277 | trait_ = path; 278 | } else { 279 | unreachable!(); 280 | } 281 | } else { 282 | return Err(syn::Error::new_spanned(first_ty_ref, "expected trait path")); 283 | } 284 | 285 | let ty = input.parse()?; 286 | if !input.is_empty() { 287 | generics.where_clause = Some(input.parse()?); 288 | } 289 | 290 | Ok(Self { 291 | impl_token, 292 | generics, 293 | trait_, 294 | for_token, 295 | ty, 296 | }) 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /src/mirror_std/from.rs: -------------------------------------------------------------------------------- 1 | //! There should be an `impl` here that corresponds to every [`From`] 2 | //! implementation in [`std`] between: 3 | //! - `[T; N]` 4 | //! - `[T]` 5 | //! - [`Vec`](alloc::vec::Vec) 6 | //! 7 | //! Here's the methodology: 8 | //! - Use the `gen` tool in this repository to scrape rustdoc 9 | //! (HTML, not JSON - it's much easier) 10 | //! - Output the `test/from.rs` file in this repository. 11 | //! This is effectively a description of the standard library conversions. 12 | //! - Redact unstable items, and the [`std::net`] conversions. 13 | //! - Switch the types from the standard library to our libraries. 14 | //! - Write implementations _in the same order_ in this file. 15 | 16 | #[cfg(feature = "std")] 17 | use core::hash::Hash; 18 | #[cfg(feature = "std")] 19 | use std::{ 20 | collections::{HashMap, HashSet}, 21 | hash::RandomState, 22 | }; 23 | 24 | #[cfg(feature = "alloc")] 25 | use alloc::{ 26 | borrow::{Cow, ToOwned}, 27 | boxed::Box, 28 | collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque}, 29 | rc::Rc, 30 | sync::Arc, 31 | }; 32 | 33 | #[cfg(feature = "alloc")] 34 | use crate::{Array, Slice, Vec}; 35 | 36 | #[cfg(feature = "alloc")] 37 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 38 | impl<'a, T> From<&'a Slice> for Cow<'a, Slice> 39 | where 40 | T: Clone, 41 | { 42 | fn from(value: &'a Slice) -> Self { 43 | Cow::Borrowed(value) 44 | } 45 | } 46 | 47 | #[cfg(feature = "alloc")] 48 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 49 | impl<'a, T> From<&'a Vec> for Cow<'a, Slice> 50 | where 51 | T: Clone, 52 | { 53 | fn from(value: &'a Vec) -> Self { 54 | Cow::Borrowed(value) 55 | } 56 | } 57 | 58 | #[cfg(feature = "alloc")] 59 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 60 | impl<'a, T> From>> for Vec 61 | where 62 | Slice: ToOwned>, 63 | { 64 | fn from(value: Cow<'a, Slice>) -> Self { 65 | value.into_owned() 66 | } 67 | } 68 | 69 | #[cfg(feature = "alloc")] 70 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 71 | impl<'a, T> From> for Cow<'a, Slice> 72 | where 73 | T: Clone, 74 | { 75 | fn from(value: Vec) -> Self { 76 | Cow::Owned(value) 77 | } 78 | } 79 | 80 | #[cfg(feature = "alloc")] 81 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 82 | impl<'a, const N: usize, T> From<&'a Array> for Cow<'a, Slice> 83 | where 84 | T: Clone, 85 | { 86 | fn from(value: &'a Array) -> Self { 87 | Cow::Borrowed(value.as_slice_ne()) 88 | } 89 | } 90 | 91 | #[cfg(feature = "std")] 92 | #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 93 | impl From> for HashMap 94 | where 95 | K: Eq + Hash, 96 | { 97 | fn from(value: Array<(K, V), N>) -> Self { 98 | value.into_iter().collect() 99 | } 100 | } 101 | 102 | #[cfg(feature = "alloc")] 103 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 104 | impl From> for BTreeMap 105 | where 106 | K: Ord, 107 | { 108 | fn from(value: Array<(K, V), N>) -> Self { 109 | value.into_iter().collect() 110 | } 111 | } 112 | 113 | #[cfg(feature = "alloc")] 114 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 115 | impl From<&Slice> for Box> 116 | where 117 | T: Clone, 118 | { 119 | fn from(value: &Slice) -> Self { 120 | let value = Box::<[T]>::from(value.as_slice()); 121 | // Safety: 122 | // - transmuting is safe because #[repr(transparent)] 123 | // - already non-empty by construction 124 | unsafe { Box::>::from_raw(Box::into_raw(value) as *mut Slice) } 125 | } 126 | } 127 | 128 | #[cfg(feature = "alloc")] 129 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 130 | impl From<&Slice> for Rc> 131 | where 132 | T: Clone, 133 | { 134 | fn from(value: &Slice) -> Self { 135 | let src = Rc::<[T]>::from(value.as_slice()); 136 | // Safety: 137 | // - transmuting is safe because #[repr(transparent)] 138 | // - already non-empty by construction 139 | unsafe { Rc::>::from_raw(Rc::into_raw(src) as *mut Slice) } 140 | } 141 | } 142 | 143 | #[cfg(feature = "alloc")] 144 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 145 | impl From<&Slice> for Arc> 146 | where 147 | T: Clone, 148 | { 149 | fn from(value: &Slice) -> Self { 150 | let value = Arc::<[T]>::from(value.as_slice()); 151 | // Safety: 152 | // - transmuting is safe because #[repr(transparent)] 153 | // - already non-empty by construction 154 | unsafe { Arc::>::from_raw(Arc::into_raw(value) as *const Slice) } 155 | } 156 | } 157 | 158 | #[cfg(feature = "alloc")] 159 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 160 | impl From<&Slice> for Vec 161 | where 162 | T: Clone, 163 | { 164 | fn from(value: &Slice) -> Self { 165 | let value = alloc::vec::Vec::from(value.as_slice()); 166 | // Safety: 167 | // - already non-empty by construction 168 | unsafe { Self::new_unchecked(value) } 169 | } 170 | } 171 | 172 | #[cfg(feature = "alloc")] 173 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 174 | impl From<&mut Slice> for Vec 175 | where 176 | T: Clone, 177 | { 178 | fn from(value: &mut Slice) -> Self { 179 | let value = alloc::vec::Vec::from(value.as_slice()); 180 | // Safety: 181 | // - already non-empty by construction 182 | unsafe { Self::new_unchecked(value) } 183 | } 184 | } 185 | 186 | #[cfg(feature = "alloc")] 187 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 188 | impl From>> for Box> 189 | where 190 | T: Clone, 191 | { 192 | fn from(value: Cow<'_, Slice>) -> Self { 193 | value.into_owned().into_boxed_slice() 194 | } 195 | } 196 | 197 | #[cfg(feature = "alloc")] 198 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 199 | impl From>> for Vec { 200 | fn from(value: Box>) -> Self { 201 | let value = Box::into_raw(value); 202 | // Safety: 203 | // - transmuting is safe because #[repr(transparent)] 204 | let value = unsafe { Box::from_raw(value as *mut [T]) }; 205 | let value = alloc::vec::Vec::from(value); 206 | // Safety: 207 | // - already non-empty by construction 208 | unsafe { Self::new_unchecked(value) } 209 | } 210 | } 211 | 212 | #[cfg(feature = "alloc")] 213 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 214 | impl From> for Box> { 215 | fn from(value: Vec) -> Self { 216 | value.into_boxed_slice() 217 | } 218 | } 219 | 220 | #[cfg(feature = "alloc")] 221 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 222 | impl From> for Rc> { 223 | fn from(value: Vec) -> Self { 224 | value.into_boxed_slice().into() 225 | } 226 | } 227 | 228 | #[cfg(feature = "alloc")] 229 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 230 | impl From> for Arc> { 231 | fn from(value: Vec) -> Self { 232 | value.into_boxed_slice().into() 233 | } 234 | } 235 | 236 | #[cfg(feature = "alloc")] 237 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 238 | impl From<&Array> for Vec 239 | where 240 | T: Clone, 241 | { 242 | fn from(value: &Array) -> Self { 243 | value.as_slice_ne().into() 244 | } 245 | } 246 | 247 | #[cfg(feature = "alloc")] 248 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 249 | impl From<&mut Array> for Vec 250 | where 251 | T: Clone, 252 | { 253 | fn from(value: &mut Array) -> Self { 254 | value.as_slice_ne().into() 255 | } 256 | } 257 | 258 | #[cfg(feature = "alloc")] 259 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 260 | impl From> for Box> { 261 | fn from(value: Array) -> Self { 262 | let value = Box::<[T]>::from(value.into_array()); 263 | // Safety: 264 | // - transmuting is safe because #[repr(transparent)] 265 | unsafe { Box::>::from_raw(Box::into_raw(value) as *mut Slice) } 266 | } 267 | } 268 | 269 | #[cfg(feature = "std")] 270 | #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 271 | impl From> for HashSet 272 | where 273 | T: Eq + Hash, 274 | { 275 | fn from(value: Array) -> Self { 276 | value.into_iter().collect() 277 | } 278 | } 279 | 280 | #[cfg(feature = "alloc")] 281 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 282 | impl From> for BTreeSet 283 | where 284 | T: Ord, 285 | { 286 | fn from(value: Array) -> Self { 287 | value.into_iter().collect() 288 | } 289 | } 290 | 291 | #[cfg(feature = "alloc")] 292 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 293 | impl From> for BinaryHeap 294 | where 295 | T: Ord, 296 | { 297 | fn from(value: Array) -> Self { 298 | value.into_iter().collect() 299 | } 300 | } 301 | 302 | #[cfg(feature = "alloc")] 303 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 304 | impl From> for LinkedList { 305 | fn from(value: Array) -> Self { 306 | value.into_iter().collect() 307 | } 308 | } 309 | 310 | #[cfg(feature = "alloc")] 311 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 312 | impl From> for VecDeque { 313 | fn from(value: Array) -> Self { 314 | value.into_iter().collect() 315 | } 316 | } 317 | 318 | #[cfg(feature = "alloc")] 319 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 320 | impl From> for Rc> { 321 | fn from(value: Array) -> Self { 322 | let value = Rc::<[T]>::from(value.into_array()); 323 | let value = Rc::into_raw(value); 324 | // Safety: 325 | // - transmuting is safe because #[repr(transparent)] 326 | unsafe { Rc::from_raw(value as *const Slice) } 327 | } 328 | } 329 | 330 | #[cfg(feature = "alloc")] 331 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 332 | impl From> for Arc> { 333 | fn from(value: Array) -> Self { 334 | let value = Arc::<[T]>::from(value.into_array()); 335 | // Safety: 336 | // - transmuting is safe because #[repr(transparent)] 337 | unsafe { Arc::>::from_raw(Arc::into_raw(value) as *const Slice) } 338 | } 339 | } 340 | 341 | #[cfg(feature = "alloc")] 342 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 343 | impl From> for Vec { 344 | fn from(value: Array) -> Self { 345 | let value = alloc::vec::Vec::from(value.into_array()); 346 | // Safety: 347 | // - already non-empty by construction 348 | unsafe { Vec::new_unchecked(value) } 349 | } 350 | } 351 | -------------------------------------------------------------------------------- /src/array.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | array, 3 | ops::{Deref, DerefMut}, 4 | }; 5 | 6 | use crate::{Array, NonEmpty, Slice}; 7 | 8 | impl Eq for NonEmpty<[T; N]> where T: Eq {} 9 | 10 | /// [`Array`] methods 11 | impl Array { 12 | /////////// 13 | // Creation 14 | /////////// 15 | 16 | crate::map_non_empty! { 17 | const 18 | /// Returns a [`NonEmpty`] array. 19 | new_ref(&[T; N]) -> &Self: Self::new_ref_unchecked; 20 | 21 | /// Returns a [`NonEmpty`] array. 22 | new_mut(&mut [T; N]) -> &mut Self: Self::new_mut_unchecked; 23 | 24 | /// Returns a [`NonEmpty`] array. 25 | new([T; N]) -> Self: Self::new_unchecked; 26 | } 27 | 28 | crate::transmuting! { 29 | const 30 | /// Create a [`NonEmpty`] array. 31 | new_ref_unchecked(&[T; N]) -> &Self; 32 | 33 | /// Create a [`NonEmpty`] array. 34 | new_mut_unchecked(&mut [T; N]) -> &mut Self; 35 | 36 | // const new_unchecked([T; N]) -> Self; // compiler can't tell this is OK 37 | } 38 | 39 | /// Create a [`NonEmpty`] array. 40 | /// 41 | /// # Safety 42 | /// - `src` must not be empty 43 | pub const unsafe fn new_unchecked(src: [T; N]) -> Self { 44 | Self { inner: src } 45 | } 46 | 47 | //////////// 48 | // Utilities 49 | //////////// 50 | 51 | /// Borrows each element and returns a [`NonEmpty`] array of references with the same size as self. 52 | pub fn each_ref(&self) -> Array<&T, N> { 53 | Array { 54 | inner: self.as_array().each_ref(), 55 | } 56 | } 57 | /// Borrows each element mutably and returns a [`NonEmpty`] array of mutable references with the same size as self. 58 | pub fn each_mut(&mut self) -> Array<&mut T, N> { 59 | Array { 60 | inner: self.as_mut_array().each_mut(), 61 | } 62 | } 63 | /// Returns a [`NonEmpty`] array of the same size as self, with function f applied to each element in order. 64 | #[doc(alias = "map")] // [`<[T; N]>::map`](https://doc.rust-lang.org/std/primitive.array.html#method.map) 65 | pub fn each_map(self, f: F) -> Array 66 | where 67 | F: FnMut(T) -> U, 68 | { 69 | Array { 70 | inner: self.into_array().map(f), 71 | } 72 | } 73 | 74 | /////////////////// 75 | // Inner references 76 | /////////////////// 77 | 78 | /// Returns a [`NonEmpty`] slice. 79 | pub const fn as_slice_ne(&self) -> &Slice { 80 | let src = self.inner.as_slice(); 81 | // Safety 82 | // - src is not empty by construction 83 | unsafe { Slice::new_unchecked(src) } 84 | } 85 | /// Returns a [`NonEmpty`] slice. 86 | pub fn as_mut_slice_ne(&mut self) -> &mut Slice { 87 | let src = self.inner.as_mut_slice(); 88 | // Safety 89 | // - src is not empty by construction 90 | unsafe { Slice::new_mut_unchecked(src) } 91 | } 92 | /// Returns a [`primitive array`](primitive@array). 93 | pub const fn as_array(&self) -> &[T; N] { 94 | &self.inner 95 | } 96 | /// Returns a [`primitive array`](primitive@array). 97 | pub fn as_mut_array(&mut self) -> &mut [T; N] { 98 | &mut self.inner 99 | } 100 | /// Returns a [`primitive array`](primitive@array). 101 | pub fn into_array(self) -> [T; N] { 102 | let Self { inner } = self; 103 | inner 104 | } 105 | } 106 | 107 | /// Known non-empty iterator for [`Array`]. 108 | impl Array { 109 | pub fn into_iter_ne(self) -> NonEmpty> { 110 | NonEmpty { 111 | inner: self.into_iter(), 112 | } 113 | } 114 | } 115 | 116 | /// Special case for [`Array`]s of length one 117 | impl Array { 118 | /// Create a [`NonEmpty`] array of a single element 119 | pub const fn of(item: T) -> Self { 120 | let src = [item]; 121 | unsafe { Self::new_unchecked(src) } 122 | } 123 | /// Create a [`NonEmpty`] array of a single mutable reference 124 | pub fn of_mut(item: &mut T) -> &mut Self { 125 | let src = array::from_mut(item); 126 | unsafe { Self::new_mut_unchecked(src) } 127 | } 128 | /// Create a [`NonEmpty`] array of a single reference 129 | pub const fn of_ref(item: &T) -> &Self { 130 | let src = array::from_ref(item); 131 | unsafe { Self::new_ref_unchecked(src) } 132 | } 133 | } 134 | 135 | /// [`Array`] to [`Slice`] 136 | impl Deref for Array { 137 | type Target = Slice; 138 | 139 | fn deref(&self) -> &Self::Target { 140 | self.as_slice_ne() 141 | } 142 | } 143 | /// [`Array`] to [`Slice`] 144 | impl DerefMut for Array { 145 | fn deref_mut(&mut self) -> &mut Self::Target { 146 | self.as_mut_slice_ne() 147 | } 148 | } 149 | 150 | crate::as_ref_as_mut! { 151 | for Array as [T]; 152 | for Array as Slice; 153 | for Array as Self; 154 | } 155 | 156 | crate::borrow_borrow_mut! { 157 | for Array as [T]; 158 | for Array as Slice; 159 | } 160 | 161 | crate::slice_iter! { 162 | for Array 163 | } 164 | 165 | impl IntoIterator for Array { 166 | type Item = T; 167 | 168 | type IntoIter = core::array::IntoIter; 169 | 170 | fn into_iter(self) -> Self::IntoIter { 171 | self.into_array().into_iter() 172 | } 173 | } 174 | 175 | mod partial_eq_std { 176 | use super::*; 177 | 178 | impl PartialEq<[U]> for Array 179 | where 180 | T: PartialEq, 181 | { 182 | fn eq(&self, other: &[U]) -> bool { 183 | <[_] as PartialEq<[_]>>::eq(self, other) 184 | } 185 | } 186 | impl PartialEq<[U; N]> for Array 187 | where 188 | T: PartialEq, 189 | { 190 | fn eq(&self, other: &[U; N]) -> bool { 191 | <[_] as PartialEq<[_]>>::eq(self, other) 192 | } 193 | } 194 | #[cfg(feature = "alloc")] 195 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 196 | impl PartialEq> for Array 197 | where 198 | T: PartialEq, 199 | { 200 | fn eq(&self, other: &alloc::vec::Vec) -> bool { 201 | <[_] as PartialEq<[_]>>::eq(self, other) 202 | } 203 | } 204 | 205 | // converse 206 | //--------- 207 | 208 | impl PartialEq> for [U] 209 | where 210 | U: PartialEq, 211 | { 212 | fn eq(&self, other: &Array) -> bool { 213 | <[_] as PartialEq<[_]>>::eq(self, other) 214 | } 215 | } 216 | impl PartialEq> for [U; N] 217 | where 218 | U: PartialEq, 219 | { 220 | fn eq(&self, other: &Array) -> bool { 221 | <[_] as PartialEq<[_]>>::eq(self, other) 222 | } 223 | } 224 | #[cfg(feature = "alloc")] 225 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 226 | impl PartialEq> for alloc::vec::Vec 227 | where 228 | U: PartialEq, 229 | { 230 | fn eq(&self, other: &Array) -> bool { 231 | <[_] as PartialEq<[_]>>::eq(self, other) 232 | } 233 | } 234 | } 235 | mod cmp_std { 236 | use core::cmp::Ordering; 237 | 238 | use super::*; 239 | 240 | impl PartialOrd<[T]> for Array 241 | where 242 | T: PartialOrd, 243 | { 244 | fn partial_cmp(&self, other: &[T]) -> Option { 245 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 246 | } 247 | } 248 | impl PartialOrd<[T; N]> for Array 249 | where 250 | T: PartialOrd, 251 | { 252 | fn partial_cmp(&self, other: &[T; N]) -> Option { 253 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 254 | } 255 | } 256 | #[cfg(feature = "alloc")] 257 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 258 | impl PartialOrd> for Array 259 | where 260 | T: PartialOrd, 261 | { 262 | fn partial_cmp(&self, other: &alloc::vec::Vec) -> Option { 263 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 264 | } 265 | } 266 | 267 | // converse 268 | //--------- 269 | 270 | impl PartialOrd> for [T] 271 | where 272 | T: PartialOrd, 273 | { 274 | fn partial_cmp(&self, other: &Array) -> Option { 275 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 276 | } 277 | } 278 | impl PartialOrd> for [T; N] 279 | where 280 | T: PartialOrd, 281 | { 282 | fn partial_cmp(&self, other: &Array) -> Option { 283 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 284 | } 285 | } 286 | #[cfg(feature = "alloc")] 287 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 288 | impl PartialOrd> for alloc::vec::Vec 289 | where 290 | T: PartialOrd, 291 | { 292 | fn partial_cmp(&self, other: &Array) -> Option { 293 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 294 | } 295 | } 296 | } 297 | 298 | mod convert_std { 299 | use crate::Error; 300 | 301 | use super::*; 302 | 303 | impl TryFrom<[T; N]> for Array { 304 | type Error = Error; 305 | 306 | fn try_from(value: [T; N]) -> Result { 307 | Self::new(value).ok_or(Error(())) 308 | } 309 | } 310 | impl<'a, T, const N: usize> TryFrom<&'a [T; N]> for &'a Array { 311 | type Error = Error; 312 | 313 | fn try_from(value: &'a [T; N]) -> Result { 314 | Array::new_ref(value).ok_or(Error(())) 315 | } 316 | } 317 | impl<'a, T, const N: usize> TryFrom<&'a mut [T; N]> for &'a mut Array { 318 | type Error = Error; 319 | 320 | fn try_from(value: &'a mut [T; N]) -> Result { 321 | Array::new_mut(value).ok_or(Error(())) 322 | } 323 | } 324 | 325 | impl From> for [T; N] { 326 | fn from(value: Array) -> Self { 327 | value.into_array() 328 | } 329 | } 330 | impl<'a, T, const N: usize> From<&'a Array> for &'a [T; N] { 331 | fn from(value: &'a Array) -> Self { 332 | value.as_array() 333 | } 334 | } 335 | impl<'a, T, const N: usize> From<&'a mut Array> for &'a mut [T; N] { 336 | fn from(value: &'a mut Array) -> Self { 337 | value.as_mut_array() 338 | } 339 | } 340 | } 341 | -------------------------------------------------------------------------------- /tests/from.rs: -------------------------------------------------------------------------------- 1 | //! See the documentation in `mirror_std/from.rs` for an explanation. 2 | 3 | #![allow(path_statements, clippy::no_effect)] 4 | 5 | use std::{ 6 | borrow::Cow, 7 | collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}, 8 | hash::{Hash, RandomState}, 9 | rc::Rc, 10 | sync::Arc, 11 | }; 12 | 13 | use nunny::Array; 14 | use nunny::Slice; 15 | use nunny::Vec; 16 | 17 | // const _: () = { 18 | // fn _test() { 19 | // > as From>>::from; 20 | // } 21 | // }; 22 | 23 | // const _: () = { 24 | // fn _test() { 25 | // > as From>>::from; 26 | // } 27 | // }; 28 | 29 | // const _: () = { 30 | // fn _test() { 31 | // >>::from; 32 | // } 33 | // }; 34 | 35 | // const _: () = { 36 | // fn _test() { 37 | // >>::from; 38 | // } 39 | // }; 40 | 41 | // const _: () = { 42 | // fn _test() { 43 | // >>::from; 44 | // } 45 | // }; 46 | 47 | // const _: () = { 48 | // fn _test() { 49 | // >>::from; 50 | // } 51 | // }; 52 | 53 | // const _: () = { 54 | // fn _test() { 55 | // >>::from; 56 | // } 57 | // }; 58 | 59 | // const _: () = { 60 | // fn _test() { 61 | // >>::from; 62 | // } 63 | // }; 64 | 65 | const _: () = { 66 | fn _test<'a, T>() 67 | where 68 | T: Clone, 69 | T: 'a, 70 | { 71 | > as From<&'a Slice>>::from; 72 | } 73 | }; 74 | 75 | const _: () = { 76 | fn _test<'a, T>() 77 | where 78 | T: Clone, 79 | T: 'a, 80 | { 81 | > as From<&'a Vec>>::from; 82 | } 83 | }; 84 | 85 | const _: () = { 86 | fn _test<'a, T>() 87 | where 88 | Slice: ToOwned>, 89 | T: 'a, 90 | { 91 | as From>>>::from; 92 | } 93 | }; 94 | 95 | const _: () = { 96 | fn _test<'a, T>() 97 | where 98 | T: Clone, 99 | T: 'a, 100 | { 101 | > as From>>::from; 102 | } 103 | }; 104 | 105 | const _: () = { 106 | fn _test<'a, T, const N: usize>() 107 | where 108 | T: Clone, 109 | T: 'a, 110 | { 111 | > as From<&'a Array>>::from; 112 | } 113 | }; 114 | 115 | // const _: () = { 116 | // fn _test<'data>() { 117 | // as From<&'data mut Slice>>::from; 118 | // } 119 | // }; 120 | 121 | // const _: () = { 122 | // fn _test<'data>() { 123 | // as From<&'data mut Slice>>>::from; 124 | // } 125 | // }; 126 | 127 | // const _: () = { 128 | // fn _test() { 129 | // > as From>>::from; 130 | // } 131 | // }; 132 | 133 | const _: () = { 134 | fn _test() 135 | where 136 | K: Eq + Hash, 137 | { 138 | as From>>::from; 139 | } 140 | }; 141 | 142 | const _: () = { 143 | fn _test() 144 | where 145 | K: Ord, 146 | { 147 | as From>>::from; 148 | } 149 | }; 150 | 151 | const _: () = { 152 | fn _test() 153 | where 154 | T: Clone, 155 | { 156 | > as From<&Slice>>::from; 157 | } 158 | }; 159 | 160 | const _: () = { 161 | fn _test() 162 | where 163 | T: Clone, 164 | { 165 | > as From<&Slice>>::from; 166 | } 167 | }; 168 | 169 | const _: () = { 170 | fn _test() 171 | where 172 | T: Clone, 173 | { 174 | > as From<&Slice>>::from; 175 | } 176 | }; 177 | 178 | const _: () = { 179 | fn _test() 180 | where 181 | T: Clone, 182 | { 183 | as From<&Slice>>::from; 184 | } 185 | }; 186 | 187 | const _: () = { 188 | fn _test() 189 | where 190 | T: Clone, 191 | { 192 | as From<&mut Slice>>::from; 193 | } 194 | }; 195 | 196 | const _: () = { 197 | fn _test() 198 | where 199 | T: Clone, 200 | { 201 | > as From>>>::from; 202 | } 203 | }; 204 | 205 | // const _: () = { 206 | // fn _test() { 207 | // <(T,) as From>>::from; 208 | // } 209 | // }; 210 | 211 | // const _: () = { 212 | // fn _test() { 213 | // <(T, T) as From>>::from; 214 | // } 215 | // }; 216 | 217 | // const _: () = { 218 | // fn _test() { 219 | // <(T, T, T) as From>>::from; 220 | // } 221 | // }; 222 | 223 | // const _: () = { 224 | // fn _test() { 225 | // <(T, T, T, T) as From>>::from; 226 | // } 227 | // }; 228 | 229 | // const _: () = { 230 | // fn _test() { 231 | // <(T, T, T, T, T) as From>>::from; 232 | // } 233 | // }; 234 | 235 | // const _: () = { 236 | // fn _test() { 237 | // <(T, T, T, T, T, T) as From>>::from; 238 | // } 239 | // }; 240 | 241 | // const _: () = { 242 | // fn _test() { 243 | // <(T, T, T, T, T, T, T) as From>>::from; 244 | // } 245 | // }; 246 | 247 | // const _: () = { 248 | // fn _test() { 249 | // <(T, T, T, T, T, T, T, T) as From>>::from; 250 | // } 251 | // }; 252 | 253 | // const _: () = { 254 | // fn _test() { 255 | // <(T, T, T, T, T, T, T, T, T) as From>>::from; 256 | // } 257 | // }; 258 | 259 | // const _: () = { 260 | // fn _test() { 261 | // <(T, T, T, T, T, T, T, T, T, T) as From>>::from; 262 | // } 263 | // }; 264 | 265 | // const _: () = { 266 | // fn _test() { 267 | // <(T, T, T, T, T, T, T, T, T, T, T) as From>>::from; 268 | // } 269 | // }; 270 | 271 | // const _: () = { 272 | // fn _test() { 273 | // <(T, T, T, T, T, T, T, T, T, T, T, T) as From>>::from; 274 | // } 275 | // }; 276 | 277 | // const _: () = { 278 | // fn _test() { 279 | // as From<(T, T)>>::from; 280 | // } 281 | // }; 282 | 283 | // const _: () = { 284 | // fn _test() { 285 | // as From<(T, T, T)>>::from; 286 | // } 287 | // }; 288 | 289 | // const _: () = { 290 | // fn _test() { 291 | // as From<(T, T, T, T)>>::from; 292 | // } 293 | // }; 294 | 295 | // const _: () = { 296 | // fn _test() { 297 | // as From<(T, T, T, T, T)>>::from; 298 | // } 299 | // }; 300 | 301 | // const _: () = { 302 | // fn _test() { 303 | // as From<(T, T, T, T, T, T)>>::from; 304 | // } 305 | // }; 306 | 307 | // const _: () = { 308 | // fn _test() { 309 | // as From<(T, T, T, T, T, T, T)>>::from; 310 | // } 311 | // }; 312 | 313 | // const _: () = { 314 | // fn _test() { 315 | // as From<(T, T, T, T, T, T, T, T)>>::from; 316 | // } 317 | // }; 318 | 319 | // const _: () = { 320 | // fn _test() { 321 | // as From<(T, T, T, T, T, T, T, T, T)>>::from; 322 | // } 323 | // }; 324 | 325 | // const _: () = { 326 | // fn _test() { 327 | // as From<(T, T, T, T, T, T, T, T, T, T)>>::from; 328 | // } 329 | // }; 330 | 331 | // const _: () = { 332 | // fn _test() { 333 | // as From<(T, T, T, T, T, T, T, T, T, T, T)>>::from; 334 | // } 335 | // }; 336 | 337 | // const _: () = { 338 | // fn _test() { 339 | // as From<(T, T, T, T, T, T, T, T, T, T, T, T)>>::from; 340 | // } 341 | // }; 342 | 343 | // const _: () = { 344 | // fn _test() { 345 | // as From<(T,)>>::from; 346 | // } 347 | // }; 348 | 349 | const _: () = { 350 | fn _test() { 351 | as From>>>::from; 352 | } 353 | }; 354 | 355 | const _: () = { 356 | fn _test() { 357 | > as From>>::from; 358 | } 359 | }; 360 | 361 | const _: () = { 362 | fn _test() { 363 | > as From>>::from; 364 | } 365 | }; 366 | 367 | const _: () = { 368 | fn _test() { 369 | > as From>>::from; 370 | } 371 | }; 372 | 373 | const _: () = { 374 | fn _test() 375 | where 376 | T: Clone, 377 | { 378 | as From<&Array>>::from; 379 | } 380 | }; 381 | 382 | const _: () = { 383 | fn _test() 384 | where 385 | T: Clone, 386 | { 387 | as From<&mut Array>>::from; 388 | } 389 | }; 390 | 391 | const _: () = { 392 | fn _test() { 393 | > as From>>::from; 394 | } 395 | }; 396 | 397 | const _: () = { 398 | fn _test() 399 | where 400 | T: Eq + Hash, 401 | { 402 | as From>>::from; 403 | } 404 | }; 405 | 406 | const _: () = { 407 | fn _test() 408 | where 409 | T: Ord, 410 | { 411 | as From>>::from; 412 | } 413 | }; 414 | 415 | const _: () = { 416 | fn _test() 417 | where 418 | T: Ord, 419 | { 420 | as From>>::from; 421 | } 422 | }; 423 | 424 | const _: () = { 425 | fn _test() { 426 | as From>>::from; 427 | } 428 | }; 429 | 430 | const _: () = { 431 | fn _test() { 432 | as From>>::from; 433 | } 434 | }; 435 | 436 | const _: () = { 437 | fn _test() { 438 | > as From>>::from; 439 | } 440 | }; 441 | 442 | // const _: () = { 443 | // fn _test() 444 | // where 445 | // LaneCount: SupportedLaneCount, 446 | // T: SimdElement, 447 | // { 448 | // as From>>::from; 449 | // } 450 | // }; 451 | 452 | const _: () = { 453 | fn _test() { 454 | > as From>>::from; 455 | } 456 | }; 457 | 458 | const _: () = { 459 | fn _test() { 460 | as From>>::from; 461 | } 462 | }; 463 | 464 | // const _: () = { 465 | // fn _test() 466 | // where 467 | // T: MaskElement, 468 | // LaneCount: SupportedLaneCount, 469 | // { 470 | // as From>>::from; 471 | // } 472 | // }; 473 | 474 | // const _: () = { 475 | // fn _test() 476 | // where 477 | // LaneCount: SupportedLaneCount, 478 | // T: SimdElement, 479 | // { 480 | // as From>>::from; 481 | // } 482 | // }; 483 | 484 | // const _: () = { 485 | // fn _test() 486 | // where 487 | // T: MaskElement, 488 | // LaneCount: SupportedLaneCount, 489 | // { 490 | // as From>>::from; 491 | // } 492 | // }; 493 | -------------------------------------------------------------------------------- /src/slice.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | num::NonZeroUsize, 3 | ops::{Deref, DerefMut}, 4 | slice, 5 | }; 6 | 7 | use crate::{NonEmpty, Slice}; 8 | 9 | impl Eq for NonEmpty<[T]> where T: Eq {} 10 | 11 | macro_rules! forward { 12 | ($($(#[$meta:meta])* pub const fn $ident:ident(&self) -> $ty:ty);* $(;)?) => { 13 | $( 14 | $(#[$meta])* 15 | pub const fn $ident(&self) -> $ty { 16 | match self.as_slice().$ident() { 17 | Some(it) => it, 18 | // Safety: 19 | // - cannot create empty slice without `unsafe` 20 | None => unsafe { crate::unreachable() }, 21 | } 22 | } 23 | )* 24 | } 25 | } 26 | macro_rules! forward_mut { 27 | ($($(#[$meta:meta])* pub fn $ident:ident(&mut self) -> $ty:ty);* $(;)?) => { 28 | $( 29 | $(#[$meta])* 30 | pub fn $ident(&mut self) -> $ty { 31 | match self.as_mut_slice().$ident() { 32 | Some(it) => it, 33 | // Safety: 34 | // - cannot create empty slice without `unsafe` 35 | None => unsafe { crate::unreachable() }, 36 | } 37 | } 38 | )* 39 | } 40 | } 41 | 42 | /// [`Slice`] methods 43 | impl Slice { 44 | /////////// 45 | // Creation 46 | /////////// 47 | 48 | crate::map_non_empty! { 49 | const 50 | /// Create a new [`NonEmpty`] slice 51 | new(&[T]) -> &Self: Self::new_unchecked; 52 | 53 | /// Create a new [`NonEmpty`] slice 54 | new_mut(&mut [T]) -> &mut Self: Self::new_mut_unchecked; 55 | } 56 | crate::transmuting! { 57 | const 58 | /// Create a new [`NonEmpty`] slice 59 | new_unchecked(&[T]) -> &Self; 60 | 61 | /// Create a new [`NonEmpty`] slice 62 | new_mut_unchecked(&mut [T]) -> &mut Self; 63 | } 64 | 65 | //////////// 66 | // Utilities 67 | //////////// 68 | 69 | /// Create a [`NonEmpty`] slice of a single element 70 | pub const fn of(item: &T) -> &Self { 71 | let shared = slice::from_ref(item); 72 | // Safety: 73 | // - len is 1 74 | unsafe { Self::new_unchecked(shared) } 75 | } 76 | /// Create a [`NonEmpty`] slice of a single element 77 | pub fn of_mut(item: &mut T) -> &mut Self { 78 | let shared = slice::from_mut(item); 79 | // Safety: 80 | // - len is 1 81 | unsafe { Self::new_mut_unchecked(shared) } 82 | } 83 | const fn check(&self) { 84 | debug_assert!(!self.inner.is_empty()); 85 | } 86 | 87 | /////////////////// 88 | // Inner references 89 | /////////////////// 90 | 91 | /// Returns a [`primitive slice`](primitive@slice). 92 | pub const fn as_slice(&self) -> &[T] { 93 | self.check(); 94 | &self.inner 95 | } 96 | /// Returns a [`primitive slice`](primitive@slice). 97 | pub fn as_mut_slice(&mut self) -> &mut [T] { 98 | self.check(); 99 | &mut self.inner 100 | } 101 | 102 | ////////////////// 103 | // Shimmed methods 104 | ////////////////// 105 | 106 | /// Returns the known non-zero length. 107 | pub const fn len_ne(&self) -> NonZeroUsize { 108 | unsafe { crate::non_zero_usize(self.inner.len()) } 109 | } 110 | forward! { 111 | /// Returns the first element, guaranteed. 112 | pub const fn first(&self) -> &T; 113 | /// Returns the first element, guaranteed, and the rest of the elements. 114 | pub const fn split_first(&self) -> (&T, &[T]); 115 | /// Returns the last element, guaranteed, and the rest of the elements. 116 | pub const fn split_last(&self) -> (&T, &[T]); 117 | /// Returns the last element, guaranteed. 118 | pub const fn last(&self) -> &T; 119 | } 120 | forward_mut! { 121 | /// Returns the first element, guaranteed. 122 | pub fn first_mut(&mut self) -> &mut T ; 123 | /// Returns the first element, guaranteed, and the rest of the elements. 124 | pub fn split_first_mut(&mut self) -> (&mut T, &mut [T]); 125 | /// Returns the last element, guaranteed, and the rest of the elements. 126 | pub fn split_last_mut(&mut self) -> (&mut T, &mut [T]); 127 | /// Returns the last element, guaranteed. 128 | pub fn last_mut(&mut self) -> &mut T; 129 | } 130 | } 131 | 132 | /// Known non-empty iterators for [`Slice`]. 133 | impl Slice { 134 | pub fn iter_ne(&self) -> NonEmpty> { 135 | NonEmpty { inner: self.iter() } 136 | } 137 | pub fn iter_mut_ne(&mut self) -> NonEmpty> { 138 | NonEmpty { 139 | inner: self.iter_mut(), 140 | } 141 | } 142 | 143 | #[cfg(feature = "alloc")] 144 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 145 | pub fn into_iter_ne(self: alloc::boxed::Box) -> NonEmpty> { 146 | crate::Vec::from(self).into_iter_ne() 147 | } 148 | } 149 | 150 | /// [`Slice`] to [`primitive slice`](primitive@slice) 151 | impl Deref for Slice { 152 | type Target = [T]; 153 | 154 | fn deref(&self) -> &Self::Target { 155 | self.as_slice() 156 | } 157 | } 158 | 159 | /// [`Slice`] to [`primitive slice`](primitive@slice) 160 | impl DerefMut for Slice { 161 | fn deref_mut(&mut self) -> &mut Self::Target { 162 | self.as_mut_slice() 163 | } 164 | } 165 | 166 | crate::as_ref_as_mut! { 167 | for Slice as [T]; 168 | for Slice as Self; 169 | } 170 | 171 | crate::borrow_borrow_mut! { 172 | for Slice as [T]; 173 | } 174 | 175 | crate::slice_iter! { 176 | for Slice 177 | } 178 | 179 | #[cfg(feature = "alloc")] 180 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 181 | impl IntoIterator for alloc::boxed::Box> { 182 | type Item = T; 183 | 184 | type IntoIter = alloc::vec::IntoIter; 185 | 186 | fn into_iter(self) -> Self::IntoIter { 187 | crate::Vec::::from(self).into_iter() 188 | } 189 | } 190 | 191 | #[cfg(feature = "alloc")] 192 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 193 | impl alloc::borrow::ToOwned for Slice 194 | where 195 | T: Clone, 196 | { 197 | type Owned = crate::Vec; 198 | 199 | fn to_owned(&self) -> Self::Owned { 200 | self.into() 201 | } 202 | } 203 | 204 | mod partial_eq_std { 205 | use super::*; 206 | 207 | impl PartialEq<[U]> for Slice 208 | where 209 | T: PartialEq, 210 | { 211 | fn eq(&self, other: &[U]) -> bool { 212 | <[_] as PartialEq<[_]>>::eq(self, other) 213 | } 214 | } 215 | impl PartialEq<[U; N]> for Slice 216 | where 217 | T: PartialEq, 218 | { 219 | fn eq(&self, other: &[U; N]) -> bool { 220 | <[_] as PartialEq<[_]>>::eq(self, other) 221 | } 222 | } 223 | #[cfg(feature = "alloc")] 224 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 225 | impl PartialEq> for Slice 226 | where 227 | T: PartialEq, 228 | { 229 | fn eq(&self, other: &alloc::vec::Vec) -> bool { 230 | <[_] as PartialEq<[_]>>::eq(self, other) 231 | } 232 | } 233 | 234 | // converse 235 | //--------- 236 | 237 | impl PartialEq> for [U] 238 | where 239 | U: PartialEq, 240 | { 241 | fn eq(&self, other: &Slice) -> bool { 242 | <[_] as PartialEq<[_]>>::eq(self, other) 243 | } 244 | } 245 | impl PartialEq> for [U; N] 246 | where 247 | U: PartialEq, 248 | { 249 | fn eq(&self, other: &Slice) -> bool { 250 | <[_] as PartialEq<[_]>>::eq(self, other) 251 | } 252 | } 253 | #[cfg(feature = "alloc")] 254 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 255 | impl PartialEq> for alloc::vec::Vec 256 | where 257 | U: PartialEq, 258 | { 259 | fn eq(&self, other: &Slice) -> bool { 260 | <[_] as PartialEq<[_]>>::eq(self, other) 261 | } 262 | } 263 | } 264 | 265 | mod cmp_std { 266 | use core::cmp::Ordering; 267 | 268 | use super::*; 269 | 270 | impl PartialOrd<[T]> for Slice 271 | where 272 | T: PartialOrd, 273 | { 274 | fn partial_cmp(&self, other: &[T]) -> Option { 275 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 276 | } 277 | } 278 | impl PartialOrd<[T; N]> for Slice 279 | where 280 | T: PartialOrd, 281 | { 282 | fn partial_cmp(&self, other: &[T; N]) -> Option { 283 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 284 | } 285 | } 286 | #[cfg(feature = "alloc")] 287 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 288 | impl PartialOrd> for Slice 289 | where 290 | T: PartialOrd, 291 | { 292 | fn partial_cmp(&self, other: &alloc::vec::Vec) -> Option { 293 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 294 | } 295 | } 296 | 297 | // converse 298 | //--------- 299 | 300 | impl PartialOrd> for [T] 301 | where 302 | T: PartialOrd, 303 | { 304 | fn partial_cmp(&self, other: &Slice) -> Option { 305 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 306 | } 307 | } 308 | impl PartialOrd> for [T; N] 309 | where 310 | T: PartialOrd, 311 | { 312 | fn partial_cmp(&self, other: &Slice) -> Option { 313 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 314 | } 315 | } 316 | #[cfg(feature = "alloc")] 317 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 318 | impl PartialOrd> for alloc::vec::Vec 319 | where 320 | T: PartialOrd, 321 | { 322 | fn partial_cmp(&self, other: &Slice) -> Option { 323 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 324 | } 325 | } 326 | } 327 | 328 | #[cfg(feature = "alloc")] 329 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 330 | impl Clone for alloc::boxed::Box> 331 | where 332 | T: Clone, 333 | { 334 | fn clone(&self) -> Self { 335 | let src = self.to_vec(); 336 | // Safety: 337 | // - Src is non-empty by construction 338 | unsafe { crate::Vec::new_unchecked(src) }.into_boxed_slice() 339 | } 340 | } 341 | 342 | mod convert_std { 343 | #[cfg(feature = "alloc")] 344 | use alloc::boxed::Box; 345 | 346 | use crate::Error; 347 | 348 | use super::*; 349 | 350 | impl<'a, T> TryFrom<&'a [T]> for &'a Slice { 351 | type Error = Error; 352 | 353 | fn try_from(value: &'a [T]) -> Result { 354 | Slice::new(value).ok_or(Error(())) 355 | } 356 | } 357 | impl<'a, T> TryFrom<&'a mut [T]> for &'a mut Slice { 358 | type Error = Error; 359 | 360 | fn try_from(value: &'a mut [T]) -> Result { 361 | Slice::new_mut(value).ok_or(Error(())) 362 | } 363 | } 364 | 365 | #[cfg(feature = "alloc")] 366 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 367 | impl TryFrom> for Box> { 368 | type Error = Error; 369 | 370 | fn try_from(value: Box<[T]>) -> Result { 371 | match crate::Vec::new(value.into_vec()) { 372 | Ok(it) => Ok(it.into_boxed_slice()), 373 | Err(_) => Err(Error(())), 374 | } 375 | } 376 | } 377 | 378 | impl<'a, T> From<&'a Slice> for &'a [T] { 379 | fn from(value: &'a Slice) -> Self { 380 | value.as_slice() 381 | } 382 | } 383 | impl<'a, T> From<&'a mut Slice> for &'a mut [T] { 384 | fn from(value: &'a mut Slice) -> Self { 385 | value.as_mut_slice() 386 | } 387 | } 388 | #[cfg(feature = "alloc")] 389 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 390 | impl From>> for Box<[T]> { 391 | fn from(value: Box>) -> Self { 392 | crate::Vec::from(value).into_vec().into_boxed_slice() 393 | } 394 | } 395 | } 396 | -------------------------------------------------------------------------------- /src/iter.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | cmp::Ordering, 3 | iter::{ 4 | Chain, Cloned, Copied, Cycle, Enumerate, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Take, 5 | }, 6 | num::NonZeroUsize, 7 | }; 8 | 9 | use crate::NonEmpty; 10 | 11 | macro_rules! unwrap { 12 | ($expr:expr) => { 13 | match $expr { 14 | Some(it) => it, 15 | // Safety: 16 | // - NonEmpty is only constructed from known NonEmpty items 17 | // - NonEmpty does give out mutable access to the inner iterator 18 | // (so it always has one element) 19 | None => unsafe { crate::unreachable() }, 20 | } 21 | }; 22 | } 23 | 24 | /// Methods on [`Iterator`]s with a non-empty invariant. 25 | /// 26 | /// See [`Self::relax`] to access the normal iterator inside. 27 | impl NonEmpty 28 | where 29 | I: Iterator, 30 | { 31 | /// [`NonEmpty`] version of [`Iterator::next`]. 32 | /// ``` 33 | /// # use nunny::{vec}; 34 | /// let v = vec![1, 2, 3]; 35 | /// let _: Option<&u8> = v.iter().next(); 36 | /// // ^ normally you have to handle the empty case 37 | /// let _: &u8 = v.iter_ne().first(); 38 | /// // ^ but we know there is at least one element 39 | /// ``` 40 | pub fn first(mut self) -> I::Item { 41 | unwrap!(self.inner.next()) 42 | } 43 | /// [`NonEmpty`] version of [`Iterator::last`]. 44 | /// ``` 45 | /// # use nunny::{vec}; 46 | /// let v = vec![1, 2, 3]; 47 | /// let _: Option<&u8> = v.iter().last(); 48 | /// // ^ normally you have to handle the empty case 49 | /// let _: &u8 = v.iter_ne().last(); 50 | /// // ^ but we know there is at least one element 51 | /// ``` 52 | pub fn last(self) -> I::Item { 53 | unwrap!(self.inner.last()) 54 | } 55 | /// [`NonEmpty`] version of [`Iterator::map`]. 56 | /// ``` 57 | /// # use nunny::{slice}; 58 | /// let iter = slice![1, 2, 3].iter_ne(); 59 | /// assert_eq!( 60 | /// iter.map(|it| *it * 2).last(), 61 | /// // ^ the invariant is maintained 62 | /// // so we _know_ there's a last element 63 | /// 6 64 | /// ); 65 | /// ``` 66 | pub fn map(self, f: F) -> NonEmpty> 67 | where 68 | F: FnMut(I::Item) -> B, 69 | { 70 | NonEmpty { 71 | inner: self.inner.map(f), 72 | } 73 | } 74 | /// [`NonEmpty`] version of [`Iterator::chain`]. 75 | /// ``` 76 | /// # use nunny::{slice}; 77 | /// let iter = slice![1, 2].iter_ne(); 78 | /// assert_eq!( 79 | /// iter.chain(&[3]).last(), 80 | /// // ^ the invariant is maintained 81 | /// // so we _know_ there's a last element 82 | /// &3 83 | /// ); 84 | /// ``` 85 | pub fn chain(self, other: U) -> NonEmpty::IntoIter>> 86 | where 87 | U: IntoIterator, 88 | { 89 | NonEmpty { 90 | inner: self.inner.chain(other), 91 | } 92 | } 93 | /// [`NonEmpty`] version of [`Iterator::enumerate`]. 94 | /// ``` 95 | /// # use nunny::{slice}; 96 | /// let iter = slice!['a', 'b'].iter_ne(); 97 | /// assert_eq!( 98 | /// iter.enumerate().last(), 99 | /// // ^ the invariant is maintained 100 | /// // so we _know_ there's a last element 101 | /// (1, &'b') 102 | /// ); 103 | /// ``` 104 | pub fn enumerate(self) -> NonEmpty> { 105 | NonEmpty { 106 | inner: self.inner.enumerate(), 107 | } 108 | } 109 | /// [`NonEmpty`] version of [`Iterator::peekable`], allowing you to use 110 | /// [`Self::peek`] and [`Self::peek_mut`] 111 | /// ``` 112 | /// # use nunny::{vec, NonEmpty}; 113 | /// let mut peek_me = vec!['a', 'b'].into_iter_ne().peekable(); 114 | /// assert_eq!( 115 | /// *peek_me.peek(), 116 | /// 'a' 117 | /// ); 118 | /// *peek_me.peek_mut() = 'b'; 119 | /// assert_eq!( 120 | /// peek_me.collect_vec(), 121 | /// ['b', 'b'] 122 | /// ); 123 | /// ``` 124 | pub fn peekable(self) -> NonEmpty> { 125 | NonEmpty { 126 | inner: self.inner.peekable(), 127 | } 128 | } 129 | /// [`NonEmpty`] version of [`Iterator::take`]. 130 | /// 131 | /// Note that `n` cannot be zero, to maintain the [`NonEmpty`] invariant. 132 | /// 133 | /// ``` 134 | /// # use nunny::{slice, nonzero}; 135 | /// let iter = slice!['a', 'b'].iter_ne(); 136 | /// assert_eq!( 137 | /// iter.take(nonzero!(1)).last(), 138 | /// // ^ compile time checked 139 | /// &'a' 140 | /// ) 141 | /// ``` 142 | pub fn take(self, n: NonZeroUsize) -> NonEmpty> { 143 | NonEmpty { 144 | inner: self.inner.take(n.get()), 145 | } 146 | } 147 | // pub fn flat_map 148 | /// [`NonEmpty`] version of [`Iterator::flatten`]. 149 | /// 150 | /// Note that the inner items must also be [`NonEmpty`], to maintain the invariant. 151 | /// ``` 152 | /// use nunny::{vec}; 153 | /// let nested = vec![vec![1], vec![2, 3]]; 154 | /// assert_eq!( 155 | /// nested.into_iter_ne().flatten().collect_vec(), 156 | /// [1, 2, 3], 157 | /// ); 158 | /// ``` 159 | #[allow(clippy::type_complexity)] 160 | pub fn flatten(self) -> NonEmpty II>> 161 | where 162 | I: Iterator>, 163 | // ^ each item is nonempty 164 | II: IntoIterator, 165 | // TODO(aatifsyed): a trait NonEmptyIterator would make this more ergonomic 166 | // See commit history for an attempt 167 | { 168 | NonEmpty { 169 | inner: self.inner.flat_map(|it| it.inner), 170 | } 171 | } 172 | /// [`NonEmpty`] version of [`Iterator::fuse`]. 173 | pub fn fuse(self) -> NonEmpty> { 174 | NonEmpty { 175 | inner: self.inner.fuse(), 176 | } 177 | } 178 | /// [`NonEmpty`] version of [`Iterator::inspect`]. 179 | pub fn inspect(self, f: F) -> NonEmpty> 180 | where 181 | F: FnMut(&I::Item), 182 | { 183 | NonEmpty { 184 | inner: self.inner.inspect(f), 185 | } 186 | } 187 | /// [`NonEmpty`] version of [`Iterator::reduce`]. 188 | /// ``` 189 | /// # use nunny::{vec}; 190 | /// # use core::cmp::min; 191 | /// let v = vec![1, 2, 3]; 192 | /// let _: Option<&u8> = v.iter().reduce(min); 193 | /// // ^ normally you have to handle the empty case 194 | /// let _: &u8 = v.iter_ne().reduce(min); 195 | /// // ^ but we know there is at least one element 196 | /// ``` 197 | pub fn reduce(self, f: F) -> I::Item 198 | where 199 | F: FnMut(I::Item, I::Item) -> I::Item, 200 | { 201 | unwrap!(self.inner.reduce(f)) 202 | } 203 | /// [`NonEmpty`] version of [`Iterator::max`]. 204 | /// ``` 205 | /// # use nunny::{vec}; 206 | /// let v = vec![1, 2, 3]; 207 | /// let _: Option<&u8> = v.iter().max(); 208 | /// // ^ normally you have to handle the empty case 209 | /// let _: &u8 = v.iter_ne().max(); 210 | /// // ^ but we know there is at least one element 211 | /// ``` 212 | pub fn max(self) -> I::Item 213 | where 214 | I::Item: Ord, 215 | { 216 | unwrap!(self.inner.max()) 217 | } 218 | /// [`NonEmpty`] version of [`Iterator::min`]. 219 | /// ``` 220 | /// # use nunny::{vec}; 221 | /// let v = vec![1, 2, 3]; 222 | /// let _: Option<&u8> = v.iter().min(); 223 | /// // ^ normally you have to handle the empty case 224 | /// let _: &u8 = v.iter_ne().min(); 225 | /// // ^ but we know there is at least one element 226 | /// ``` 227 | pub fn min(self) -> I::Item 228 | where 229 | I::Item: Ord, 230 | { 231 | unwrap!(self.inner.min()) 232 | } 233 | /// [`NonEmpty`] version of [`Iterator::max_by_key`]. 234 | pub fn max_by_key(self, f: F) -> I::Item 235 | where 236 | B: Ord, 237 | F: FnMut(&I::Item) -> B, 238 | { 239 | unwrap!(self.inner.max_by_key(f)) 240 | } 241 | /// [`NonEmpty`] version of [`Iterator::max_by`]. 242 | pub fn max_by(self, compare: F) -> I::Item 243 | where 244 | F: FnMut(&I::Item, &I::Item) -> Ordering, 245 | { 246 | unwrap!(self.inner.max_by(compare)) 247 | } 248 | /// [`NonEmpty`] version of [`Iterator::min_by_key`]. 249 | pub fn min_by_key(self, f: F) -> I::Item 250 | where 251 | B: Ord, 252 | F: FnMut(&I::Item) -> B, 253 | { 254 | unwrap!(self.inner.min_by_key(f)) 255 | } 256 | /// [`NonEmpty`] version of [`Iterator::min_by`]. 257 | pub fn min_by(self, compare: F) -> I::Item 258 | where 259 | F: FnMut(&I::Item, &I::Item) -> Ordering, 260 | { 261 | unwrap!(self.inner.min_by(compare)) 262 | } 263 | /// [`NonEmpty`] version of [`Iterator::rev`]. 264 | pub fn rev(self) -> NonEmpty> 265 | where 266 | I: DoubleEndedIterator, 267 | { 268 | NonEmpty { 269 | inner: self.inner.rev(), 270 | } 271 | } 272 | 273 | /// [`NonEmpty`] version of [`Iterator::unzip`]. 274 | #[cfg(feature = "alloc")] 275 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 276 | pub fn unzip_vec(self) -> (crate::Vec, crate::Vec) 277 | where 278 | I: Iterator, 279 | { 280 | let (a, b) = self.inner.unzip(); 281 | // Safety: 282 | // - NonEmpty is only constructed from known NonEmpty items 283 | // - NonEmpty does not allow mutable access to the inner iterator 284 | // (so it always has one element) 285 | unsafe { (crate::Vec::new_unchecked(a), crate::Vec::new_unchecked(b)) } 286 | } 287 | /// [`NonEmpty`] version of [`Iterator::copied`]. 288 | pub fn copied<'a, T>(self) -> NonEmpty> 289 | where 290 | T: 'a + Copy, 291 | I: Iterator, 292 | { 293 | NonEmpty { 294 | inner: self.inner.copied(), 295 | } 296 | } 297 | /// [`NonEmpty`] version of [`Iterator::cloned`]. 298 | pub fn cloned<'a, T>(self) -> NonEmpty> 299 | where 300 | T: 'a + Clone, 301 | I: Iterator, 302 | { 303 | NonEmpty { 304 | inner: self.inner.cloned(), 305 | } 306 | } 307 | /// [`NonEmpty`] version of [`Iterator::cycle`]. 308 | pub fn cycle(self) -> NonEmpty> 309 | where 310 | I: Clone, 311 | { 312 | NonEmpty { 313 | inner: self.inner.cycle(), 314 | } 315 | } 316 | /// Remove the [`NonEmpty`] wrapper, allowing you to access normal iterator 317 | /// methods like [`Iterator::filter`]. 318 | #[doc(alias = "into_iter")] 319 | #[doc(alias = "into_inner")] 320 | pub fn relax(self) -> I { 321 | self.inner 322 | } 323 | /// Collect this iterator into a [`NonEmpty`]. 324 | #[cfg(feature = "alloc")] 325 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 326 | pub fn collect_vec(self) -> crate::Vec { 327 | // Safety: 328 | // - NonEmpty is only constructed from known NonEmpty items 329 | // - NonEmpty does not allow mutable access to the inner iterator 330 | // (so it always has one element) 331 | unsafe { crate::Vec::new_unchecked(self.inner.collect()) } 332 | } 333 | /// Collect [`Ok`] items into a [`NonEmpty`], short-circuiting on [`Err`]. 334 | #[cfg(feature = "alloc")] 335 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 336 | pub fn try_collect_vec(self) -> Result, E> 337 | where 338 | I: Iterator>, 339 | { 340 | match self.inner.collect() { 341 | // Safety: 342 | // - NonEmpty is only constructed from known NonEmpty items 343 | // - NonEmpty does not allow mutable access to the inner iterator 344 | // (so it always has one element) 345 | Ok(it) => Ok(unsafe { crate::Vec::new_unchecked(it) }), 346 | Err(e) => Err(e), 347 | } 348 | } 349 | } 350 | 351 | impl NonEmpty> 352 | where 353 | I: Iterator, 354 | { 355 | /// Peek this [`NonEmpty`] iterator, without advancing it. 356 | /// 357 | /// See [`Self::peekable`]. 358 | pub fn peek(&mut self) -> &I::Item { 359 | unwrap!(self.inner.peek()) 360 | } 361 | /// Peek and modify this [`NonEmpty`] iterator, without advancing it. 362 | /// 363 | /// See [`Self::peekable`]. 364 | pub fn peek_mut(&mut self) -> &mut I::Item { 365 | unwrap!(self.inner.peek_mut()) 366 | } 367 | } 368 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The definitive non-empty slice/array/vec library for Rust. 2 | //! 3 | //! # Features 4 | //! Nonempty-by-construction API 5 | //! ``` 6 | //! # use nunny::NonEmpty; 7 | //! let mut my_vec = NonEmpty::>::of("hello"); // construct once 8 | //! my_vec.push("world"); // continue using your normal APIs 9 | //! let hello: &str = my_vec.first(); // preserve the guarantee that there is at least one element 10 | //! ``` 11 | //! 12 | //! `#[repr(transparent)]` allows advanced usecases and guarantees optimum performance[^1]: 13 | //! ``` 14 | //! # use nunny::NonEmpty; 15 | //! let src = &mut ["hello", "world"]; 16 | //! let ne = NonEmpty::<[_]>::new_mut(src).unwrap(); 17 | //! // ^ uses the same backing memory 18 | //! let world: &str = ne.last(); 19 | //! ``` 20 | //! 21 | //! Total API coverage. 22 | //! For every impl of [`From`], [`TryFrom`], [`PartialEq`] and [`PartialOrd`] in [`std`][^2], 23 | //! there is a corresponding impl in this library for [`Slice`], [`Array`] and [`Vec`]. 24 | //! _This includes more exotic types_: 25 | //! ``` 26 | //! # use nunny::{vec, NonEmpty}; 27 | //! # use std::{borrow::Cow, sync::Arc}; 28 | //! let nun: Box> = vec![0xDEAD, 0xBEEF].into(); 29 | //! let cow: Cow> = (&*nun).into(); 30 | //! let arc: Arc> = cow.into_owned().into(); 31 | //! ``` 32 | //! 33 | //! `const`-friendly API. Where possible, all methods are `const`. 34 | //! ``` 35 | //! # use nunny::{NonEmpty, slice}; 36 | //! const TWO: &NonEmpty<[&str]> = slice!["together", "forever"]; 37 | //! const FIRST: &str = TWO.first(); 38 | //! const ONE: &NonEmpty<[&str]> = NonEmpty::<[_]>::of(&"lonely"); 39 | //! ``` 40 | //! 41 | //! Extensive feature gating supporting: 42 | //! - `no-std` environments with no allocator. 43 | //! - `alloc`-enabled environments. 44 | //! - full-`std`-enabled environments. 45 | //! - interaction with crates like [`serde`](::serde1) and [`arbitrary`](::arbitrary1). 46 | //! 47 | //! Iterator support: 48 | //! Specialized [`Iterator`] methods remove branches to handle empty iterators, 49 | //! _and_ preserve invariants even when chaining combinators. 50 | //! ``` 51 | //! # use nunny::{vec}; 52 | //! let v = vec![1, 2, 3]; 53 | //! let _: Option<&u8> = v.iter().last(); 54 | //! // ^ normally you have to handle the empty case 55 | //! let _: &u8 = v.iter_ne().last(); 56 | //! // ^ but we know there is at least one element 57 | //! let _: u8 = v.iter_ne().copied().last(); 58 | //! // ^ using this combinator preserves the invariant 59 | //! ``` 60 | //! 61 | //! Thoughtful design: 62 | //! - [`NonZeroUsize`] is inserted [where](Slice::len_ne) [appropriate](Vec::truncate). 63 | //! - Everything [`Deref`](core::ops::Deref)/[`DerefMut`](core::ops::DerefMut)s 64 | //! down to a [`NonEmpty>`], which in turn `deref/mut`s down to a `[T]`. 65 | //! - Liberal applications of [`cmp`](core::cmp), [`borrow`](core::borrow), [`convert`](core::convert) 66 | //! traits. 67 | //! If there's a missing API that you'd like, please raise an issue! 68 | //! 69 | //! [^1]: Other crates like [`nonempty`](https://docs.rs/nonempty/latest/nonempty/struct.NonEmpty.html) 70 | //! require an indirection. 71 | //! [^2]: Barring impls on `!#[fundamental]` types like [`Arc`](std::sync::Arc). 72 | //! Fun fact: our tests were generated from [`std`]'s rustdoc! 73 | 74 | #![cfg_attr(not(feature = "std"), no_std)] 75 | #![cfg_attr(docsrs, feature(doc_cfg))] 76 | 77 | #[cfg(feature = "alloc")] 78 | extern crate alloc; 79 | #[cfg(feature = "arbitrary1")] 80 | #[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))] 81 | mod arbitrary1; 82 | #[cfg(feature = "proptest1")] 83 | #[cfg_attr(docsrs, doc(cfg(feature = "proptest")))] 84 | mod proptest1; 85 | #[cfg(feature = "quickcheck1")] 86 | #[cfg_attr(docsrs, doc(cfg(feature = "quickcheck")))] 87 | mod quickcheck1; 88 | #[cfg(feature = "schemars08")] 89 | #[cfg_attr(docsrs, doc(cfg(feature = "schemars")))] 90 | mod schemars08; 91 | #[cfg(feature = "schemars09")] 92 | #[cfg_attr(docsrs, doc(cfg(feature = "schemars")))] 93 | mod schemars09; 94 | #[cfg(feature = "schemars1")] 95 | #[cfg_attr(docsrs, doc(cfg(feature = "schemars")))] 96 | mod schemars1; 97 | #[cfg(feature = "serde1")] 98 | #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] 99 | mod serde1; 100 | 101 | mod array; 102 | mod iter; 103 | mod mirror_std { 104 | mod cmp; 105 | mod from; 106 | mod partial_eq; 107 | mod try_from; 108 | } 109 | mod slice; 110 | #[cfg(feature = "alloc")] 111 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 112 | mod vec; 113 | 114 | use core::{convert::Infallible, fmt, num::NonZeroUsize}; 115 | 116 | /// A wrapper struct around non-empty slices/arrays/vectors. 117 | /// 118 | /// You may wish to use the following type aliases instead: 119 | /// - [`Slice`]. 120 | /// - [`Vec`]. 121 | /// - [`Array`]. 122 | /// 123 | /// See also [crate documentation](crate) 124 | #[derive(Debug, Clone, Copy, Hash)] 125 | #[repr(transparent)] 126 | pub struct NonEmpty { 127 | inner: T, 128 | } 129 | 130 | /// A non-empty [prim@array] of known size. 131 | pub type Array = NonEmpty<[T; N]>; 132 | /// A non-empty, dynamically sized [prim@slice]. 133 | pub type Slice = NonEmpty<[T]>; 134 | /// A non-empty, heap allocated [Vec](alloc::vec::Vec). 135 | #[cfg(feature = "alloc")] 136 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 137 | pub type Vec = NonEmpty>; 138 | 139 | /// Create a non-empty slice 140 | /// ``` 141 | /// # use nunny::{NonEmpty, slice}; 142 | /// const SLICE: &NonEmpty<[&str]> = slice!["hello", "world"]; 143 | /// ``` 144 | /// 145 | /// Note that no `slice_mut` is provided[^1] - users are expected to use [`array!`] 146 | /// and [`Array::as_mut_slice`] as required. 147 | /// 148 | /// [^1]: See [this blog post](https://blog.m-ou.se/super-let/) for more on why 149 | /// `slice_mut` is impossible to implement in Rust today. 150 | #[macro_export] 151 | macro_rules! slice { 152 | ($($el:expr),+ $(,)?) => { 153 | // Safety: 154 | // - `+` guarantees that at least one item is given 155 | unsafe { 156 | $crate::Slice::new_unchecked(&[$($el),*]) 157 | } 158 | }; 159 | } 160 | 161 | /// Create a non-empty array 162 | /// ``` 163 | /// # use nunny::array; 164 | /// let mut arr = array!["hello", "world"]; 165 | /// *arr.first_mut() = "goodbye"; 166 | /// assert_eq!(arr, ["goodbye", "world"]) 167 | /// ``` 168 | #[macro_export] 169 | macro_rules! array { 170 | ($($el:expr),+ $(,)?) => { 171 | // Safety: 172 | // - `+` guarantees that at least one item is given 173 | unsafe { 174 | $crate::Array::new_unchecked([$($el),*]) 175 | } 176 | }; 177 | } 178 | 179 | /// Create a non-empty heap-allocated vector 180 | /// ``` 181 | /// # use nunny::{NonEmpty, vec}; 182 | /// let mut v = vec!["hello", "world"]; 183 | /// *v.first_mut() = "goodbye"; 184 | /// assert_eq!(v, ["goodbye", "world"]) 185 | /// ``` 186 | /// 187 | /// For `vec![T; N]`, `N` must be evaluatable at `const` time, and `T` must be [`Clone`]. 188 | /// ```compile_fail 189 | /// # use nunny::vec; 190 | /// let len = 1 + 1; // runtime variable 191 | /// let v = vec!["hello"; len]; 192 | /// ``` 193 | /// ``` 194 | /// # use nunny::vec; 195 | /// let v = vec!["hello"; 1 + 1]; // compile time nonzero 196 | /// ``` 197 | /// ```compile_fail 198 | /// # use nunny::vec; 199 | /// let v = vec!["hello"; 0]; // not allowed to be zero! 200 | /// ``` 201 | #[cfg(feature = "alloc")] 202 | #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] 203 | #[macro_export] 204 | macro_rules! vec { 205 | ($($el:expr),+ $(,)?) => { 206 | // Safety: 207 | // - `+` guarantees that at least one item is given 208 | $crate::Vec::from(unsafe { 209 | $crate::Array::new_unchecked([$($el),*]) 210 | }) 211 | }; 212 | ($el:expr; $n:expr) => { 213 | $crate::Vec::filled($el, $crate::nonzero!($n)) 214 | } 215 | } 216 | 217 | /// Checks that an expression is non-zero _at compile time_. 218 | /// 219 | /// Provided as a convenience for writing tests. 220 | /// 221 | /// ``` 222 | /// # use core::num::NonZeroUsize; 223 | /// # use nunny::nonzero; 224 | /// const NONZERO: NonZeroUsize = nonzero!(1); 225 | /// ``` 226 | /// ```compile_fail 227 | /// # use core::num::NonZeroUsize; 228 | /// # use nunny::nonzero; 229 | /// const OOPS: NonZeroUsize = nonzero!(0); 230 | /// ``` 231 | #[doc(hidden)] 232 | #[macro_export] 233 | macro_rules! nonzero { 234 | ($expr:expr) => {{ 235 | const NONZERO: $crate::__private::core::num::NonZeroUsize = 236 | match $crate::__private::core::num::NonZeroUsize::new($expr) { 237 | $crate::__private::core::option::Option::Some(it) => it, 238 | _ => $crate::__private::core::panic!("expression evaluated to zero"), 239 | }; 240 | NONZERO 241 | }}; 242 | } 243 | 244 | /// Implementation detail, semver-exempt. 245 | #[doc(hidden)] 246 | pub mod __private { 247 | pub extern crate core; 248 | } 249 | 250 | /// Error returned in [`TryFrom`] implementations for reference conversions. 251 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 252 | pub struct Error(()); 253 | 254 | impl fmt::Display for Error { 255 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 256 | f.write_str("collection was empty") 257 | } 258 | } 259 | 260 | #[cfg(feature = "std")] 261 | impl std::error::Error for Error {} 262 | 263 | macro_rules! transmuting { 264 | () => {}; // base case 265 | (const $(#[$meta:meta])* $ident:ident($in:ty) -> $out:ty; $($rest:tt)*) => { 266 | $(#[$meta])* 267 | /// 268 | /// # Safety 269 | /// - `src` must not be empty 270 | pub const unsafe fn $ident(src: $in) -> $out { 271 | debug_assert!(!src.is_empty()); 272 | // Safety 273 | // - #[repr(transparent)] 274 | unsafe { core::mem::transmute(src) } 275 | } 276 | $crate::transmuting!($($rest)*); 277 | }; 278 | ($(#[$meta:meta])* $ident:ident($in:ty) -> $out:ty; $($rest:tt)*) => { 279 | $(#[$meta])* 280 | /// 281 | /// # Safety 282 | /// - `src` must not be empty 283 | pub unsafe fn $ident(src: $in) -> $out { 284 | debug_assert!(!src.is_empty()); 285 | // Safety 286 | // - #[repr(transparent)] 287 | unsafe { core::mem::transmute(src) } 288 | } 289 | $crate::transmuting!($($rest)*); 290 | }; 291 | } 292 | pub(crate) use transmuting; 293 | 294 | macro_rules! map_non_empty { 295 | () => {}; // base case 296 | (const $(#[$meta:meta])* $ident:ident($in:ty) -> $out:ty: $mapper:path; $($rest:tt)*) => { 297 | $(#[$meta])* 298 | /// 299 | /// Returns [`None`] if `src` is empty. 300 | pub const fn $ident(src: $in) -> Option<$out> { 301 | match src.is_empty() { 302 | true => None, 303 | // Safety 304 | // - checked non empty 305 | false => Some(unsafe { $mapper(src) }) 306 | } 307 | } 308 | $crate::map_non_empty!($($rest)*); 309 | }; 310 | ($(#[$meta:meta])* $ident:ident($in:ty) -> $out:ty: $mapper:path; $($rest:tt)*) => { 311 | $(#[$meta])* 312 | /// 313 | /// Returns [`None`] if `src` is empty. 314 | pub fn $ident(src: $in) -> Option<$out> { 315 | match src.is_empty() { 316 | true => None, 317 | // Safety 318 | // - checked non empty 319 | false => Some(unsafe { $mapper(src) }) 320 | } 321 | } 322 | $crate::map_non_empty!($($rest)*); 323 | }; 324 | } 325 | pub(crate) use map_non_empty; 326 | 327 | macro_rules! as_ref_as_mut { 328 | ($($(<$ty_param:ident $(, const $const_param:ident: usize)?>)? for $self:ty as $ty:ty);* $(;)?) => { 329 | $( 330 | impl$(<$ty_param $(, const $const_param: usize)?>)? ::core::convert::AsRef<$ty> for $self { 331 | fn as_ref(&self) -> &$ty { self } 332 | } 333 | 334 | impl$(<$ty_param $(, const $const_param: usize)?>)? ::core::convert::AsMut<$ty> for $self { 335 | fn as_mut(&mut self) -> &mut $ty { self } 336 | } 337 | 338 | )* 339 | }; 340 | } 341 | pub(crate) use as_ref_as_mut; 342 | 343 | macro_rules! borrow_borrow_mut { 344 | ($($(<$ty_param:ident $(, const $const_param:ident: usize)?>)? for $self:ty as $ty:ty);* $(;)?) => { 345 | $( 346 | impl$(<$ty_param $(, const $const_param: usize)?>)? ::core::borrow::Borrow<$ty> for $self { 347 | fn borrow(&self) -> &$ty { self } 348 | } 349 | 350 | impl$(<$ty_param $(, const $const_param: usize)?>)? ::core::borrow::BorrowMut<$ty> for $self { 351 | fn borrow_mut(&mut self) -> &mut $ty { self } 352 | } 353 | 354 | )* 355 | }; 356 | } 357 | pub(crate) use borrow_borrow_mut; 358 | 359 | macro_rules! slice_iter { 360 | (<$ty_param:ident $(, const $const_param:ident: usize)?> for $self:ty) => { 361 | impl<'a, $ty_param $(, const $const_param: usize)?> ::core::iter::IntoIterator for &'a $self { 362 | type Item = &'a $ty_param; 363 | type IntoIter = ::core::slice::Iter<'a, T>; 364 | fn into_iter(self) -> Self::IntoIter { 365 | self.iter() 366 | } 367 | } 368 | 369 | impl<'a, $ty_param $(, const $const_param: usize)?> ::core::iter::IntoIterator for &'a mut $self { 370 | type Item = &'a mut $ty_param; 371 | type IntoIter = ::core::slice::IterMut<'a, T>; 372 | fn into_iter(self) -> Self::IntoIter { 373 | self.iter_mut() 374 | } 375 | } 376 | }; 377 | } 378 | pub(crate) use slice_iter; 379 | 380 | #[track_caller] 381 | const unsafe fn non_zero_usize(n: usize) -> NonZeroUsize { 382 | match NonZeroUsize::new(n) { 383 | Some(it) => it, 384 | None => unreachable(), 385 | } 386 | } 387 | 388 | #[track_caller] 389 | const unsafe fn unreachable() -> ! { 390 | match cfg!(debug_assertions) { 391 | true => unreachable(), 392 | false => unsafe { core::hint::unreachable_unchecked() }, 393 | } 394 | } 395 | 396 | /// Error returned in [`TryFrom`] implementations for reference conversions. 397 | #[derive(Debug, Clone, Copy)] 398 | pub struct TryFromSliceError(()); 399 | 400 | impl From for TryFromSliceError { 401 | fn from(value: Infallible) -> Self { 402 | match value {} 403 | } 404 | } 405 | 406 | impl fmt::Display for TryFromSliceError { 407 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 408 | f.write_str("could not convert slice to array") 409 | } 410 | } 411 | -------------------------------------------------------------------------------- /src/vec.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | mem::MaybeUninit, 3 | num::NonZeroUsize, 4 | ops::{Deref, DerefMut}, 5 | }; 6 | 7 | use alloc::{boxed::Box, collections::TryReserveError}; 8 | 9 | use crate::{NonEmpty, Slice, Vec}; 10 | 11 | impl Eq for NonEmpty> where T: Eq {} 12 | impl PartialEq> for Vec 13 | where 14 | T: PartialEq, 15 | { 16 | fn eq(&self, other: &Vec) -> bool { 17 | <[_] as PartialEq<[U]>>::eq(self, other) 18 | } 19 | } 20 | 21 | macro_rules! forward_mut { 22 | ($( $(#[$meta:meta])* $vis:vis fn $ident:ident(&mut self $(,$arg:ident: $ty:ty)* $(,)?) $(-> $ret:ty)?);* $(;)?) => { 23 | $( 24 | $(#[$meta])* 25 | /// 26 | #[doc = concat!("See [`", stringify!($ident), "`](alloc::vec::Vec::", stringify!($ident), ").")] 27 | $vis fn $ident(&mut self $(, $arg: $ty)*) $(-> $ret)? { 28 | // Safety: 29 | // - operation does not remove elements 30 | unsafe { self.as_mut_vec() }.$ident($($arg),*) 31 | } 32 | )* 33 | }; 34 | } 35 | 36 | /// [`Vec`] methods 37 | impl Vec { 38 | /////////// 39 | // Creation 40 | /////////// 41 | 42 | crate::map_non_empty! { 43 | /// Create a new [`NonEmpty`] heap-allocated vec 44 | new_ref(&alloc::vec::Vec) -> &Self: Self::new_ref_unchecked; 45 | /// Create a new [`NonEmpty`] heap-allocated vec 46 | new_mut(&mut alloc::vec::Vec) -> &mut Self: Self::new_mut_unchecked; 47 | } 48 | crate::transmuting! { 49 | /// Create a new [`NonEmpty`] heap-allocated vec 50 | new_unchecked(alloc::vec::Vec) -> Self; 51 | /// Create a new [`NonEmpty`] heap-allocated vec 52 | new_ref_unchecked(&alloc::vec::Vec) -> &Self; 53 | /// Create a new [`NonEmpty`] heap-allocated vec 54 | new_mut_unchecked(&mut alloc::vec::Vec) -> &mut Self; 55 | } 56 | /// Create a new [`NonEmpty`] heap-allocated vec, returning the original 57 | /// allocation if it was empty. 58 | pub fn new(src: alloc::vec::Vec) -> Result> { 59 | match src.is_empty() { 60 | false => Ok(unsafe { Self::new_unchecked(src) }), 61 | true => Err(src), 62 | } 63 | } 64 | 65 | //////////// 66 | // Utilities 67 | //////////// 68 | 69 | /// Create a [`NonEmpty`] heap-allocated vec, of a single element. 70 | pub fn of(item: T) -> Self { 71 | Self::of_with_capacity(item, 1) 72 | } 73 | /// Create a [`NonEmpty`] heap-allocated vec, of a single element, with 74 | /// capacity for `capacity` elements without (re)-allocating. 75 | pub fn of_with_capacity(item: T, capacity: usize) -> Self { 76 | let mut inner = alloc::vec::Vec::with_capacity(capacity); 77 | inner.push(item); 78 | // Safety: 79 | // - pushing the element succeeded 80 | unsafe { Self::new_unchecked(inner) } 81 | } 82 | /// Creating a [`NonEmpty`] heap-allocated vec where the first element is known. 83 | /// 84 | /// This is an convenience method, equivalent to 85 | /// ``` 86 | /// let mut it = nunny::vec!["first"]; 87 | /// it.extend(["this", "is", "the", "rest"]); 88 | /// ``` 89 | pub fn of_extending(first: T, rest: impl IntoIterator) -> Self 90 | where 91 | Self: Extend, 92 | { 93 | let rest = rest.into_iter(); 94 | let mut this = Self::of_with_capacity(first, rest.size_hint().0); 95 | this.extend(rest); 96 | this 97 | } 98 | 99 | /// Create a [`NonEmpty`] heap-allocated vec with `len` items, filled with 100 | /// [`Clone`]s of the given `value`. 101 | /// 102 | /// See also [`Self::filled_with`]. 103 | pub fn filled(value: T, len: NonZeroUsize) -> Self 104 | where 105 | T: Clone, 106 | { 107 | let mut inner = alloc::vec::Vec::new(); 108 | inner.resize(len.get(), value); 109 | // Safety: 110 | // - len is nonzero 111 | unsafe { Self::new_unchecked(inner) } 112 | } 113 | 114 | /// Create a [`NonEmpty`] heap-allocated vec with `len` items, filled with 115 | /// values returned from repeating the closure `f`. 116 | /// 117 | /// See also [`Self::filled`]. 118 | pub fn filled_with(f: F, len: NonZeroUsize) -> Self 119 | where 120 | F: FnMut() -> T, 121 | { 122 | let mut inner = alloc::vec::Vec::new(); 123 | inner.resize_with(len.get(), f); 124 | // Safety: 125 | // - len is nonzero 126 | unsafe { Self::new_unchecked(inner) } 127 | } 128 | fn check(&self) { 129 | debug_assert_ne!(self.inner.len(), 0) 130 | } 131 | 132 | /// Returns a [`std::vec::Vec`]. 133 | pub fn as_vec(&self) -> &alloc::vec::Vec { 134 | self.check(); 135 | &self.inner 136 | } 137 | /// Returns a [`std::vec::Vec`]. 138 | /// 139 | /// # Safety 140 | /// - returned vec must not be emptied through this reference 141 | pub unsafe fn as_mut_vec(&mut self) -> &mut alloc::vec::Vec { 142 | self.check(); 143 | &mut self.inner 144 | } 145 | /// Returns a [`std::vec::Vec`]. 146 | pub fn into_vec(self) -> alloc::vec::Vec { 147 | let Self { inner } = self; 148 | inner 149 | } 150 | /// Returns a [`NonEmpty`] slice. 151 | pub fn as_slice_ne(&self) -> &Slice { 152 | unsafe { Slice::new_unchecked(self.as_vec()) } 153 | } 154 | /// Returns a [`NonEmpty`] slice. 155 | pub fn as_mut_slice_ne(&mut self) -> &mut Slice { 156 | unsafe { Slice::new_mut_unchecked(self.as_mut_vec()) } 157 | } 158 | 159 | ////////////////// 160 | // Shimmed methods (rustdoc order) 161 | ////////////////// 162 | 163 | /// Returns the known non-zero length. 164 | pub fn capacity(&self) -> NonZeroUsize { 165 | self.check(); 166 | unsafe { crate::non_zero_usize(self.as_vec().capacity()) } 167 | } 168 | 169 | forward_mut! { 170 | pub fn reserve(&mut self, additional: usize); 171 | pub fn reserve_exact(&mut self, additional: usize); 172 | pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError>; 173 | pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError>; 174 | pub fn shrink_to_fit(&mut self); 175 | pub fn shrink_to(&mut self, min_capacity: usize); 176 | } 177 | 178 | /// Return a [`NonEmpty`] boxed slice. 179 | pub fn into_boxed_slice(self) -> Box> { 180 | match cfg!(debug_assertions) { 181 | true => { 182 | let src = self.into_vec().into_boxed_slice(); 183 | let len0 = src.len(); 184 | let ptr = Box::into_raw(src); 185 | // Safety: 186 | // - #[repr(transparent)] 187 | let dst = unsafe { Box::from_raw(ptr as *mut Slice) }; 188 | let len1 = dst.len_ne().get(); 189 | assert_eq!(len0, len1); 190 | dst 191 | } 192 | false => { 193 | let ptr = Box::into_raw(self.into_vec().into_boxed_slice()); 194 | // Safety: 195 | // - #[repr(transparent)] 196 | unsafe { Box::from_raw(ptr as *mut Slice) } 197 | } 198 | } 199 | } 200 | 201 | /// Shortens the vector to a guaranteed-nonzero length 202 | /// 203 | /// See [`truncate`](alloc::vec::Vec::truncate). 204 | pub fn truncate(&mut self, len: NonZeroUsize) { 205 | // Safety: 206 | // - len is not zero, so vector will not be emptied 207 | unsafe { self.as_mut_vec() }.truncate(len.get()); 208 | self.check(); 209 | } 210 | 211 | /// # Safety 212 | /// - See [`set_len`](alloc::vec::Vec::set_len). 213 | pub unsafe fn set_len(&mut self, new_len: NonZeroUsize) { 214 | // Safety: 215 | // - len is not zero, so vector will not be emptied 216 | unsafe { self.as_mut_vec() }.set_len(new_len.get()); 217 | self.check(); 218 | } 219 | 220 | forward_mut! { 221 | pub fn insert(&mut self, index: usize, element: T); 222 | } 223 | 224 | /// See [`dedup_by_key`](alloc::vec::Vec::dedup_by_key). 225 | pub fn dedup_by_key(&mut self, key: F) 226 | where 227 | F: FnMut(&mut T) -> K, 228 | K: PartialEq, 229 | { 230 | // Safety: 231 | // - dedup always leaves the first element 232 | unsafe { self.as_mut_vec() }.dedup_by_key(key); 233 | self.check(); 234 | } 235 | /// See [`dedup_by`](alloc::vec::Vec::dedup_by). 236 | pub fn dedup_by(&mut self, same_bucket: F) 237 | where 238 | F: FnMut(&mut T, &mut T) -> bool, 239 | { 240 | // Safety: 241 | // - dedup always leaves the first element 242 | unsafe { self.as_mut_vec() }.dedup_by(same_bucket); 243 | self.check(); 244 | } 245 | forward_mut! { 246 | pub fn push(&mut self, value: T); 247 | pub fn append(&mut self, other: &mut alloc::vec::Vec); 248 | } 249 | 250 | // pub fn split_off(&mut self, at: NonZeroUsize) 251 | 252 | /// See [`resize_with`](alloc::vec::Vec::resize_with). 253 | pub fn resize_with(&mut self, new_len: NonZeroUsize, f: F) 254 | where 255 | F: FnMut() -> T, 256 | { 257 | // Safety: 258 | // - new_len is not zero, so vec cannot be emptied 259 | unsafe { self.as_mut_vec() }.resize_with(new_len.get(), f); 260 | self.check(); 261 | } 262 | /// Returns a [`NonEmpty`] slice. 263 | /// 264 | /// See [`leak`](alloc::vec::Vec::leak). 265 | pub fn leak<'a>(self) -> &'a mut Slice { 266 | let inner = self.into_vec().leak(); 267 | // Safety: 268 | // - originating slice is non-empty by construction 269 | unsafe { Slice::new_mut_unchecked(inner) } 270 | } 271 | forward_mut! { 272 | pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit]; 273 | } 274 | } 275 | 276 | /// Known non-empty iterator for [`Vec`]. 277 | impl Vec { 278 | pub fn into_iter_ne(self) -> NonEmpty> { 279 | NonEmpty { 280 | inner: self.into_vec().into_iter(), 281 | } 282 | } 283 | } 284 | 285 | /// [`Vec`] to [`Slice`] 286 | impl Deref for Vec { 287 | type Target = Slice; 288 | 289 | fn deref(&self) -> &Self::Target { 290 | self.as_slice_ne() 291 | } 292 | } 293 | 294 | /// [`Vec`] to [`Slice`] 295 | impl DerefMut for Vec { 296 | fn deref_mut(&mut self) -> &mut Self::Target { 297 | self.as_mut_slice_ne() 298 | } 299 | } 300 | 301 | crate::as_ref_as_mut! { 302 | for Vec as [T]; 303 | for Vec as Slice; 304 | for Vec as Self; 305 | } 306 | 307 | crate::borrow_borrow_mut! { 308 | for Vec as [T]; 309 | for Vec as Slice; 310 | } 311 | 312 | crate::slice_iter! { 313 | for Vec 314 | } 315 | 316 | mod iter { 317 | use super::*; 318 | impl IntoIterator for Vec { 319 | type Item = T; 320 | 321 | type IntoIter = alloc::vec::IntoIter; 322 | 323 | fn into_iter(self) -> Self::IntoIter { 324 | self.into_vec().into_iter() 325 | } 326 | } 327 | impl<'a, T> Extend<&'a T> for Vec 328 | where 329 | T: Copy + 'a, 330 | { 331 | fn extend>(&mut self, iter: II) { 332 | // Safety: 333 | // - append-only operation 334 | unsafe { self.as_mut_vec() }.extend(iter) 335 | } 336 | } 337 | impl Extend for Vec { 338 | fn extend>(&mut self, iter: II) { 339 | // Safety: 340 | // - append-only operation 341 | unsafe { self.as_mut_vec() }.extend(iter) 342 | } 343 | } 344 | } 345 | 346 | mod partial_eq_std { 347 | use super::*; 348 | 349 | impl PartialEq<[U]> for Vec 350 | where 351 | T: PartialEq, 352 | { 353 | fn eq(&self, other: &[U]) -> bool { 354 | <[_] as PartialEq<[_]>>::eq(self, other) 355 | } 356 | } 357 | impl PartialEq<[U; N]> for Vec 358 | where 359 | T: PartialEq, 360 | { 361 | fn eq(&self, other: &[U; N]) -> bool { 362 | <[_] as PartialEq<[_]>>::eq(self, other) 363 | } 364 | } 365 | impl PartialEq> for Vec 366 | where 367 | T: PartialEq, 368 | { 369 | fn eq(&self, other: &alloc::vec::Vec) -> bool { 370 | <[_] as PartialEq<[_]>>::eq(self, other) 371 | } 372 | } 373 | 374 | // converse 375 | //--------- 376 | 377 | impl PartialEq> for [U] 378 | where 379 | U: PartialEq, 380 | { 381 | fn eq(&self, other: &Vec) -> bool { 382 | <[_] as PartialEq<[_]>>::eq(self, other) 383 | } 384 | } 385 | impl PartialEq> for [U; N] 386 | where 387 | U: PartialEq, 388 | { 389 | fn eq(&self, other: &Vec) -> bool { 390 | <[_] as PartialEq<[_]>>::eq(self, other) 391 | } 392 | } 393 | impl PartialEq> for alloc::vec::Vec 394 | where 395 | U: PartialEq, 396 | { 397 | fn eq(&self, other: &Vec) -> bool { 398 | <[_] as PartialEq<[_]>>::eq(self, other) 399 | } 400 | } 401 | } 402 | 403 | mod cmp_std { 404 | use core::cmp::Ordering; 405 | 406 | use super::*; 407 | 408 | impl PartialOrd<[T]> for Vec 409 | where 410 | T: PartialOrd, 411 | { 412 | fn partial_cmp(&self, other: &[T]) -> Option { 413 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 414 | } 415 | } 416 | impl PartialOrd<[T; N]> for Vec 417 | where 418 | T: PartialOrd, 419 | { 420 | fn partial_cmp(&self, other: &[T; N]) -> Option { 421 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 422 | } 423 | } 424 | 425 | impl PartialOrd> for Vec 426 | where 427 | T: PartialOrd, 428 | { 429 | fn partial_cmp(&self, other: &alloc::vec::Vec) -> Option { 430 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 431 | } 432 | } 433 | 434 | // converse 435 | //--------- 436 | 437 | impl PartialOrd> for [T] 438 | where 439 | T: PartialOrd, 440 | { 441 | fn partial_cmp(&self, other: &Vec) -> Option { 442 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 443 | } 444 | } 445 | impl PartialOrd> for [T; N] 446 | where 447 | T: PartialOrd, 448 | { 449 | fn partial_cmp(&self, other: &Vec) -> Option { 450 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 451 | } 452 | } 453 | impl PartialOrd> for alloc::vec::Vec 454 | where 455 | T: PartialOrd, 456 | { 457 | fn partial_cmp(&self, other: &Vec) -> Option { 458 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 459 | } 460 | } 461 | } 462 | 463 | mod convert_std { 464 | use crate::Error; 465 | 466 | use super::*; 467 | 468 | impl TryFrom> for Vec { 469 | type Error = alloc::vec::Vec; 470 | 471 | fn try_from(value: alloc::vec::Vec) -> Result { 472 | Vec::new(value) 473 | } 474 | } 475 | impl<'a, T> TryFrom<&'a alloc::vec::Vec> for &'a Vec { 476 | type Error = Error; 477 | 478 | fn try_from(value: &'a alloc::vec::Vec) -> Result { 479 | Vec::new_ref(value).ok_or(Error(())) 480 | } 481 | } 482 | impl<'a, T> TryFrom<&'a mut alloc::vec::Vec> for &'a mut Vec { 483 | type Error = Error; 484 | 485 | fn try_from(value: &'a mut alloc::vec::Vec) -> Result { 486 | Vec::new_mut(value).ok_or(Error(())) 487 | } 488 | } 489 | 490 | impl From> for alloc::vec::Vec { 491 | fn from(value: Vec) -> Self { 492 | value.into_vec() 493 | } 494 | } 495 | impl<'a, T> From<&'a Vec> for &'a alloc::vec::Vec { 496 | fn from(value: &'a Vec) -> Self { 497 | value.as_vec() 498 | } 499 | } 500 | } 501 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.1" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" 19 | 20 | [[package]] 21 | name = "ahash" 22 | version = "0.8.12" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" 25 | dependencies = [ 26 | "cfg-if", 27 | "getrandom 0.3.3", 28 | "once_cell", 29 | "version_check", 30 | "zerocopy", 31 | ] 32 | 33 | [[package]] 34 | name = "aho-corasick" 35 | version = "1.1.3" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 38 | dependencies = [ 39 | "memchr", 40 | ] 41 | 42 | [[package]] 43 | name = "anstream" 44 | version = "0.6.19" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" 47 | dependencies = [ 48 | "anstyle", 49 | "anstyle-parse", 50 | "anstyle-query", 51 | "anstyle-wincon", 52 | "colorchoice", 53 | "is_terminal_polyfill", 54 | "utf8parse", 55 | ] 56 | 57 | [[package]] 58 | name = "anstyle" 59 | version = "1.0.11" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" 62 | 63 | [[package]] 64 | name = "anstyle-parse" 65 | version = "0.2.7" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" 68 | dependencies = [ 69 | "utf8parse", 70 | ] 71 | 72 | [[package]] 73 | name = "anstyle-query" 74 | version = "1.1.3" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" 77 | dependencies = [ 78 | "windows-sys 0.59.0", 79 | ] 80 | 81 | [[package]] 82 | name = "anstyle-wincon" 83 | version = "3.0.9" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" 86 | dependencies = [ 87 | "anstyle", 88 | "once_cell_polyfill", 89 | "windows-sys 0.59.0", 90 | ] 91 | 92 | [[package]] 93 | name = "anyhow" 94 | version = "1.0.98" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" 97 | 98 | [[package]] 99 | name = "arbitrary" 100 | version = "1.4.1" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" 103 | 104 | [[package]] 105 | name = "autocfg" 106 | version = "1.5.0" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" 109 | 110 | [[package]] 111 | name = "backtrace" 112 | version = "0.3.75" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" 115 | dependencies = [ 116 | "addr2line", 117 | "cfg-if", 118 | "libc", 119 | "miniz_oxide", 120 | "object", 121 | "rustc-demangle", 122 | "windows-targets 0.52.6", 123 | ] 124 | 125 | [[package]] 126 | name = "backtrace-ext" 127 | version = "0.2.1" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" 130 | dependencies = [ 131 | "backtrace", 132 | ] 133 | 134 | [[package]] 135 | name = "base64" 136 | version = "0.22.1" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 139 | 140 | [[package]] 141 | name = "bit-set" 142 | version = "0.8.0" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" 145 | dependencies = [ 146 | "bit-vec", 147 | ] 148 | 149 | [[package]] 150 | name = "bit-vec" 151 | version = "0.8.0" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" 154 | 155 | [[package]] 156 | name = "bitflags" 157 | version = "2.9.1" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" 160 | 161 | [[package]] 162 | name = "byteorder" 163 | version = "1.5.0" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 166 | 167 | [[package]] 168 | name = "cc" 169 | version = "1.2.27" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" 172 | dependencies = [ 173 | "shlex", 174 | ] 175 | 176 | [[package]] 177 | name = "cfg-if" 178 | version = "1.0.1" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" 181 | 182 | [[package]] 183 | name = "clap" 184 | version = "4.5.40" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" 187 | dependencies = [ 188 | "clap_builder", 189 | "clap_derive", 190 | ] 191 | 192 | [[package]] 193 | name = "clap_builder" 194 | version = "4.5.40" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" 197 | dependencies = [ 198 | "anstream", 199 | "anstyle", 200 | "clap_lex", 201 | "strsim", 202 | "terminal_size", 203 | ] 204 | 205 | [[package]] 206 | name = "clap_derive" 207 | version = "4.5.40" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" 210 | dependencies = [ 211 | "heck", 212 | "proc-macro2", 213 | "quote", 214 | "syn", 215 | ] 216 | 217 | [[package]] 218 | name = "clap_lex" 219 | version = "0.7.5" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" 222 | 223 | [[package]] 224 | name = "colorchoice" 225 | version = "1.0.4" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" 228 | 229 | [[package]] 230 | name = "condtype" 231 | version = "1.3.0" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "baf0a07a401f374238ab8e2f11a104d2851bf9ce711ec69804834de8af45c7af" 234 | 235 | [[package]] 236 | name = "crc32fast" 237 | version = "1.4.2" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 240 | dependencies = [ 241 | "cfg-if", 242 | ] 243 | 244 | [[package]] 245 | name = "cssparser" 246 | version = "0.31.2" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "5b3df4f93e5fbbe73ec01ec8d3f68bba73107993a5b1e7519273c32db9b0d5be" 249 | dependencies = [ 250 | "cssparser-macros", 251 | "dtoa-short", 252 | "itoa", 253 | "phf 0.11.3", 254 | "smallvec", 255 | ] 256 | 257 | [[package]] 258 | name = "cssparser-macros" 259 | version = "0.6.1" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" 262 | dependencies = [ 263 | "quote", 264 | "syn", 265 | ] 266 | 267 | [[package]] 268 | name = "derive_more" 269 | version = "0.99.20" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" 272 | dependencies = [ 273 | "proc-macro2", 274 | "quote", 275 | "syn", 276 | ] 277 | 278 | [[package]] 279 | name = "displaydoc" 280 | version = "0.2.5" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 283 | dependencies = [ 284 | "proc-macro2", 285 | "quote", 286 | "syn", 287 | ] 288 | 289 | [[package]] 290 | name = "divan" 291 | version = "0.1.14" 292 | source = "git+https://github.com/OliverKillane/divan?branch=enh%2Ffile-output#c54ac74a8b85e3862a4bcbaea9e08d9e5095caa5" 293 | dependencies = [ 294 | "cfg-if", 295 | "clap", 296 | "condtype", 297 | "divan-macros", 298 | "libc", 299 | "regex-lite", 300 | "serde_json", 301 | ] 302 | 303 | [[package]] 304 | name = "divan-macros" 305 | version = "0.1.14" 306 | source = "git+https://github.com/OliverKillane/divan?branch=enh%2Ffile-output#c54ac74a8b85e3862a4bcbaea9e08d9e5095caa5" 307 | dependencies = [ 308 | "proc-macro2", 309 | "quote", 310 | "syn", 311 | ] 312 | 313 | [[package]] 314 | name = "dtoa" 315 | version = "1.0.10" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" 318 | 319 | [[package]] 320 | name = "dtoa-short" 321 | version = "0.3.5" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" 324 | dependencies = [ 325 | "dtoa", 326 | ] 327 | 328 | [[package]] 329 | name = "dyn-clone" 330 | version = "1.0.19" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" 333 | 334 | [[package]] 335 | name = "ego-tree" 336 | version = "0.6.3" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "12a0bb14ac04a9fcf170d0bbbef949b44cc492f4452bd20c095636956f653642" 339 | 340 | [[package]] 341 | name = "errno" 342 | version = "0.3.13" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" 345 | dependencies = [ 346 | "libc", 347 | "windows-sys 0.60.2", 348 | ] 349 | 350 | [[package]] 351 | name = "fastrand" 352 | version = "2.3.0" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 355 | 356 | [[package]] 357 | name = "flate2" 358 | version = "1.1.2" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" 361 | dependencies = [ 362 | "crc32fast", 363 | "miniz_oxide", 364 | ] 365 | 366 | [[package]] 367 | name = "fnv" 368 | version = "1.0.7" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 371 | 372 | [[package]] 373 | name = "form_urlencoded" 374 | version = "1.2.1" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 377 | dependencies = [ 378 | "percent-encoding", 379 | ] 380 | 381 | [[package]] 382 | name = "futf" 383 | version = "0.1.5" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" 386 | dependencies = [ 387 | "mac", 388 | "new_debug_unreachable", 389 | ] 390 | 391 | [[package]] 392 | name = "fxhash" 393 | version = "0.2.1" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" 396 | dependencies = [ 397 | "byteorder", 398 | ] 399 | 400 | [[package]] 401 | name = "gen" 402 | version = "0.0.0" 403 | dependencies = [ 404 | "anyhow", 405 | "clap", 406 | "owo-colors", 407 | "prettyplease", 408 | "proc-macro2", 409 | "quote", 410 | "regex", 411 | "scraper", 412 | "syn", 413 | "syn-miette", 414 | "ureq", 415 | ] 416 | 417 | [[package]] 418 | name = "getopts" 419 | version = "0.2.23" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" 422 | dependencies = [ 423 | "unicode-width 0.2.1", 424 | ] 425 | 426 | [[package]] 427 | name = "getrandom" 428 | version = "0.2.16" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" 431 | dependencies = [ 432 | "cfg-if", 433 | "libc", 434 | "wasi 0.11.1+wasi-snapshot-preview1", 435 | ] 436 | 437 | [[package]] 438 | name = "getrandom" 439 | version = "0.3.3" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" 442 | dependencies = [ 443 | "cfg-if", 444 | "libc", 445 | "r-efi", 446 | "wasi 0.14.2+wasi-0.2.4", 447 | ] 448 | 449 | [[package]] 450 | name = "gimli" 451 | version = "0.31.1" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 454 | 455 | [[package]] 456 | name = "heck" 457 | version = "0.5.0" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 460 | 461 | [[package]] 462 | name = "html5ever" 463 | version = "0.27.0" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" 466 | dependencies = [ 467 | "log", 468 | "mac", 469 | "markup5ever", 470 | "proc-macro2", 471 | "quote", 472 | "syn", 473 | ] 474 | 475 | [[package]] 476 | name = "icu_collections" 477 | version = "2.0.0" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" 480 | dependencies = [ 481 | "displaydoc", 482 | "potential_utf", 483 | "yoke", 484 | "zerofrom", 485 | "zerovec", 486 | ] 487 | 488 | [[package]] 489 | name = "icu_locale_core" 490 | version = "2.0.0" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" 493 | dependencies = [ 494 | "displaydoc", 495 | "litemap", 496 | "tinystr", 497 | "writeable", 498 | "zerovec", 499 | ] 500 | 501 | [[package]] 502 | name = "icu_normalizer" 503 | version = "2.0.0" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" 506 | dependencies = [ 507 | "displaydoc", 508 | "icu_collections", 509 | "icu_normalizer_data", 510 | "icu_properties", 511 | "icu_provider", 512 | "smallvec", 513 | "zerovec", 514 | ] 515 | 516 | [[package]] 517 | name = "icu_normalizer_data" 518 | version = "2.0.0" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" 521 | 522 | [[package]] 523 | name = "icu_properties" 524 | version = "2.0.1" 525 | source = "registry+https://github.com/rust-lang/crates.io-index" 526 | checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" 527 | dependencies = [ 528 | "displaydoc", 529 | "icu_collections", 530 | "icu_locale_core", 531 | "icu_properties_data", 532 | "icu_provider", 533 | "potential_utf", 534 | "zerotrie", 535 | "zerovec", 536 | ] 537 | 538 | [[package]] 539 | name = "icu_properties_data" 540 | version = "2.0.1" 541 | source = "registry+https://github.com/rust-lang/crates.io-index" 542 | checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" 543 | 544 | [[package]] 545 | name = "icu_provider" 546 | version = "2.0.0" 547 | source = "registry+https://github.com/rust-lang/crates.io-index" 548 | checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" 549 | dependencies = [ 550 | "displaydoc", 551 | "icu_locale_core", 552 | "stable_deref_trait", 553 | "tinystr", 554 | "writeable", 555 | "yoke", 556 | "zerofrom", 557 | "zerotrie", 558 | "zerovec", 559 | ] 560 | 561 | [[package]] 562 | name = "idna" 563 | version = "1.0.3" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 566 | dependencies = [ 567 | "idna_adapter", 568 | "smallvec", 569 | "utf8_iter", 570 | ] 571 | 572 | [[package]] 573 | name = "idna_adapter" 574 | version = "1.2.1" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" 577 | dependencies = [ 578 | "icu_normalizer", 579 | "icu_properties", 580 | ] 581 | 582 | [[package]] 583 | name = "is_ci" 584 | version = "1.2.0" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" 587 | 588 | [[package]] 589 | name = "is_terminal_polyfill" 590 | version = "1.70.1" 591 | source = "registry+https://github.com/rust-lang/crates.io-index" 592 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 593 | 594 | [[package]] 595 | name = "itoa" 596 | version = "1.0.15" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 599 | 600 | [[package]] 601 | name = "lazy_static" 602 | version = "1.5.0" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 605 | 606 | [[package]] 607 | name = "libc" 608 | version = "0.2.174" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" 611 | 612 | [[package]] 613 | name = "linux-raw-sys" 614 | version = "0.9.4" 615 | source = "registry+https://github.com/rust-lang/crates.io-index" 616 | checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" 617 | 618 | [[package]] 619 | name = "litemap" 620 | version = "0.8.0" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" 623 | 624 | [[package]] 625 | name = "lock_api" 626 | version = "0.4.13" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" 629 | dependencies = [ 630 | "autocfg", 631 | "scopeguard", 632 | ] 633 | 634 | [[package]] 635 | name = "log" 636 | version = "0.4.27" 637 | source = "registry+https://github.com/rust-lang/crates.io-index" 638 | checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 639 | 640 | [[package]] 641 | name = "mac" 642 | version = "0.1.1" 643 | source = "registry+https://github.com/rust-lang/crates.io-index" 644 | checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" 645 | 646 | [[package]] 647 | name = "markup5ever" 648 | version = "0.12.1" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45" 651 | dependencies = [ 652 | "log", 653 | "phf 0.11.3", 654 | "phf_codegen 0.11.3", 655 | "string_cache", 656 | "string_cache_codegen", 657 | "tendril", 658 | ] 659 | 660 | [[package]] 661 | name = "memchr" 662 | version = "2.7.5" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" 665 | 666 | [[package]] 667 | name = "miette" 668 | version = "7.6.0" 669 | source = "registry+https://github.com/rust-lang/crates.io-index" 670 | checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" 671 | dependencies = [ 672 | "backtrace", 673 | "backtrace-ext", 674 | "cfg-if", 675 | "miette-derive", 676 | "owo-colors", 677 | "supports-color", 678 | "supports-hyperlinks", 679 | "supports-unicode", 680 | "terminal_size", 681 | "textwrap", 682 | "unicode-width 0.1.14", 683 | ] 684 | 685 | [[package]] 686 | name = "miette-derive" 687 | version = "7.6.0" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" 690 | dependencies = [ 691 | "proc-macro2", 692 | "quote", 693 | "syn", 694 | ] 695 | 696 | [[package]] 697 | name = "miniz_oxide" 698 | version = "0.8.9" 699 | source = "registry+https://github.com/rust-lang/crates.io-index" 700 | checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" 701 | dependencies = [ 702 | "adler2", 703 | ] 704 | 705 | [[package]] 706 | name = "new_debug_unreachable" 707 | version = "1.0.6" 708 | source = "registry+https://github.com/rust-lang/crates.io-index" 709 | checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" 710 | 711 | [[package]] 712 | name = "nonempty" 713 | version = "0.11.0" 714 | source = "registry+https://github.com/rust-lang/crates.io-index" 715 | checksum = "549e471b99ccaf2f89101bec68f4d244457d5a95a9c3d0672e9564124397741d" 716 | 717 | [[package]] 718 | name = "num-traits" 719 | version = "0.2.19" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 722 | dependencies = [ 723 | "autocfg", 724 | ] 725 | 726 | [[package]] 727 | name = "nunny" 728 | version = "0.2.2" 729 | dependencies = [ 730 | "arbitrary", 731 | "divan", 732 | "nonempty", 733 | "proptest", 734 | "quickcheck", 735 | "schemars 0.8.22", 736 | "schemars 0.9.0", 737 | "schemars 1.0.0", 738 | "serde", 739 | "serde_json", 740 | ] 741 | 742 | [[package]] 743 | name = "object" 744 | version = "0.36.7" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 747 | dependencies = [ 748 | "memchr", 749 | ] 750 | 751 | [[package]] 752 | name = "once_cell" 753 | version = "1.21.3" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 756 | 757 | [[package]] 758 | name = "once_cell_polyfill" 759 | version = "1.70.1" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" 762 | 763 | [[package]] 764 | name = "owo-colors" 765 | version = "4.2.1" 766 | source = "registry+https://github.com/rust-lang/crates.io-index" 767 | checksum = "26995317201fa17f3656c36716aed4a7c81743a9634ac4c99c0eeda495db0cec" 768 | 769 | [[package]] 770 | name = "parking_lot" 771 | version = "0.12.4" 772 | source = "registry+https://github.com/rust-lang/crates.io-index" 773 | checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" 774 | dependencies = [ 775 | "lock_api", 776 | "parking_lot_core", 777 | ] 778 | 779 | [[package]] 780 | name = "parking_lot_core" 781 | version = "0.9.11" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" 784 | dependencies = [ 785 | "cfg-if", 786 | "libc", 787 | "redox_syscall", 788 | "smallvec", 789 | "windows-targets 0.52.6", 790 | ] 791 | 792 | [[package]] 793 | name = "percent-encoding" 794 | version = "2.3.1" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 797 | 798 | [[package]] 799 | name = "phf" 800 | version = "0.10.1" 801 | source = "registry+https://github.com/rust-lang/crates.io-index" 802 | checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" 803 | dependencies = [ 804 | "phf_shared 0.10.0", 805 | ] 806 | 807 | [[package]] 808 | name = "phf" 809 | version = "0.11.3" 810 | source = "registry+https://github.com/rust-lang/crates.io-index" 811 | checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" 812 | dependencies = [ 813 | "phf_macros", 814 | "phf_shared 0.11.3", 815 | ] 816 | 817 | [[package]] 818 | name = "phf_codegen" 819 | version = "0.10.0" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" 822 | dependencies = [ 823 | "phf_generator 0.10.0", 824 | "phf_shared 0.10.0", 825 | ] 826 | 827 | [[package]] 828 | name = "phf_codegen" 829 | version = "0.11.3" 830 | source = "registry+https://github.com/rust-lang/crates.io-index" 831 | checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" 832 | dependencies = [ 833 | "phf_generator 0.11.3", 834 | "phf_shared 0.11.3", 835 | ] 836 | 837 | [[package]] 838 | name = "phf_generator" 839 | version = "0.10.0" 840 | source = "registry+https://github.com/rust-lang/crates.io-index" 841 | checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" 842 | dependencies = [ 843 | "phf_shared 0.10.0", 844 | "rand 0.8.5", 845 | ] 846 | 847 | [[package]] 848 | name = "phf_generator" 849 | version = "0.11.3" 850 | source = "registry+https://github.com/rust-lang/crates.io-index" 851 | checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" 852 | dependencies = [ 853 | "phf_shared 0.11.3", 854 | "rand 0.8.5", 855 | ] 856 | 857 | [[package]] 858 | name = "phf_macros" 859 | version = "0.11.3" 860 | source = "registry+https://github.com/rust-lang/crates.io-index" 861 | checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" 862 | dependencies = [ 863 | "phf_generator 0.11.3", 864 | "phf_shared 0.11.3", 865 | "proc-macro2", 866 | "quote", 867 | "syn", 868 | ] 869 | 870 | [[package]] 871 | name = "phf_shared" 872 | version = "0.10.0" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" 875 | dependencies = [ 876 | "siphasher 0.3.11", 877 | ] 878 | 879 | [[package]] 880 | name = "phf_shared" 881 | version = "0.11.3" 882 | source = "registry+https://github.com/rust-lang/crates.io-index" 883 | checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" 884 | dependencies = [ 885 | "siphasher 1.0.1", 886 | ] 887 | 888 | [[package]] 889 | name = "potential_utf" 890 | version = "0.1.2" 891 | source = "registry+https://github.com/rust-lang/crates.io-index" 892 | checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" 893 | dependencies = [ 894 | "zerovec", 895 | ] 896 | 897 | [[package]] 898 | name = "ppv-lite86" 899 | version = "0.2.21" 900 | source = "registry+https://github.com/rust-lang/crates.io-index" 901 | checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" 902 | dependencies = [ 903 | "zerocopy", 904 | ] 905 | 906 | [[package]] 907 | name = "precomputed-hash" 908 | version = "0.1.1" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" 911 | 912 | [[package]] 913 | name = "prettyplease" 914 | version = "0.2.35" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a" 917 | dependencies = [ 918 | "proc-macro2", 919 | "syn", 920 | ] 921 | 922 | [[package]] 923 | name = "proc-macro2" 924 | version = "1.0.95" 925 | source = "registry+https://github.com/rust-lang/crates.io-index" 926 | checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" 927 | dependencies = [ 928 | "unicode-ident", 929 | ] 930 | 931 | [[package]] 932 | name = "proptest" 933 | version = "1.7.0" 934 | source = "registry+https://github.com/rust-lang/crates.io-index" 935 | checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" 936 | dependencies = [ 937 | "bit-set", 938 | "bit-vec", 939 | "bitflags", 940 | "lazy_static", 941 | "num-traits", 942 | "rand 0.9.1", 943 | "rand_chacha 0.9.0", 944 | "rand_xorshift", 945 | "regex-syntax", 946 | "rusty-fork", 947 | "tempfile", 948 | "unarray", 949 | ] 950 | 951 | [[package]] 952 | name = "quick-error" 953 | version = "1.2.3" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 956 | 957 | [[package]] 958 | name = "quickcheck" 959 | version = "1.0.3" 960 | source = "registry+https://github.com/rust-lang/crates.io-index" 961 | checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" 962 | dependencies = [ 963 | "rand 0.8.5", 964 | ] 965 | 966 | [[package]] 967 | name = "quote" 968 | version = "1.0.40" 969 | source = "registry+https://github.com/rust-lang/crates.io-index" 970 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 971 | dependencies = [ 972 | "proc-macro2", 973 | ] 974 | 975 | [[package]] 976 | name = "r-efi" 977 | version = "5.3.0" 978 | source = "registry+https://github.com/rust-lang/crates.io-index" 979 | checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" 980 | 981 | [[package]] 982 | name = "rand" 983 | version = "0.8.5" 984 | source = "registry+https://github.com/rust-lang/crates.io-index" 985 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 986 | dependencies = [ 987 | "libc", 988 | "rand_chacha 0.3.1", 989 | "rand_core 0.6.4", 990 | ] 991 | 992 | [[package]] 993 | name = "rand" 994 | version = "0.9.1" 995 | source = "registry+https://github.com/rust-lang/crates.io-index" 996 | checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" 997 | dependencies = [ 998 | "rand_chacha 0.9.0", 999 | "rand_core 0.9.3", 1000 | ] 1001 | 1002 | [[package]] 1003 | name = "rand_chacha" 1004 | version = "0.3.1" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1007 | dependencies = [ 1008 | "ppv-lite86", 1009 | "rand_core 0.6.4", 1010 | ] 1011 | 1012 | [[package]] 1013 | name = "rand_chacha" 1014 | version = "0.9.0" 1015 | source = "registry+https://github.com/rust-lang/crates.io-index" 1016 | checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 1017 | dependencies = [ 1018 | "ppv-lite86", 1019 | "rand_core 0.9.3", 1020 | ] 1021 | 1022 | [[package]] 1023 | name = "rand_core" 1024 | version = "0.6.4" 1025 | source = "registry+https://github.com/rust-lang/crates.io-index" 1026 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1027 | dependencies = [ 1028 | "getrandom 0.2.16", 1029 | ] 1030 | 1031 | [[package]] 1032 | name = "rand_core" 1033 | version = "0.9.3" 1034 | source = "registry+https://github.com/rust-lang/crates.io-index" 1035 | checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" 1036 | dependencies = [ 1037 | "getrandom 0.3.3", 1038 | ] 1039 | 1040 | [[package]] 1041 | name = "rand_xorshift" 1042 | version = "0.4.0" 1043 | source = "registry+https://github.com/rust-lang/crates.io-index" 1044 | checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" 1045 | dependencies = [ 1046 | "rand_core 0.9.3", 1047 | ] 1048 | 1049 | [[package]] 1050 | name = "redox_syscall" 1051 | version = "0.5.13" 1052 | source = "registry+https://github.com/rust-lang/crates.io-index" 1053 | checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" 1054 | dependencies = [ 1055 | "bitflags", 1056 | ] 1057 | 1058 | [[package]] 1059 | name = "ref-cast" 1060 | version = "1.0.24" 1061 | source = "registry+https://github.com/rust-lang/crates.io-index" 1062 | checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" 1063 | dependencies = [ 1064 | "ref-cast-impl", 1065 | ] 1066 | 1067 | [[package]] 1068 | name = "ref-cast-impl" 1069 | version = "1.0.24" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" 1072 | dependencies = [ 1073 | "proc-macro2", 1074 | "quote", 1075 | "syn", 1076 | ] 1077 | 1078 | [[package]] 1079 | name = "regex" 1080 | version = "1.11.1" 1081 | source = "registry+https://github.com/rust-lang/crates.io-index" 1082 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 1083 | dependencies = [ 1084 | "aho-corasick", 1085 | "memchr", 1086 | "regex-automata", 1087 | "regex-syntax", 1088 | ] 1089 | 1090 | [[package]] 1091 | name = "regex-automata" 1092 | version = "0.4.9" 1093 | source = "registry+https://github.com/rust-lang/crates.io-index" 1094 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 1095 | dependencies = [ 1096 | "aho-corasick", 1097 | "memchr", 1098 | "regex-syntax", 1099 | ] 1100 | 1101 | [[package]] 1102 | name = "regex-lite" 1103 | version = "0.1.6" 1104 | source = "registry+https://github.com/rust-lang/crates.io-index" 1105 | checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" 1106 | 1107 | [[package]] 1108 | name = "regex-syntax" 1109 | version = "0.8.5" 1110 | source = "registry+https://github.com/rust-lang/crates.io-index" 1111 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1112 | 1113 | [[package]] 1114 | name = "ring" 1115 | version = "0.17.14" 1116 | source = "registry+https://github.com/rust-lang/crates.io-index" 1117 | checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" 1118 | dependencies = [ 1119 | "cc", 1120 | "cfg-if", 1121 | "getrandom 0.2.16", 1122 | "libc", 1123 | "untrusted", 1124 | "windows-sys 0.52.0", 1125 | ] 1126 | 1127 | [[package]] 1128 | name = "rustc-demangle" 1129 | version = "0.1.25" 1130 | source = "registry+https://github.com/rust-lang/crates.io-index" 1131 | checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" 1132 | 1133 | [[package]] 1134 | name = "rustix" 1135 | version = "1.0.7" 1136 | source = "registry+https://github.com/rust-lang/crates.io-index" 1137 | checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" 1138 | dependencies = [ 1139 | "bitflags", 1140 | "errno", 1141 | "libc", 1142 | "linux-raw-sys", 1143 | "windows-sys 0.59.0", 1144 | ] 1145 | 1146 | [[package]] 1147 | name = "rustls" 1148 | version = "0.23.28" 1149 | source = "registry+https://github.com/rust-lang/crates.io-index" 1150 | checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" 1151 | dependencies = [ 1152 | "log", 1153 | "once_cell", 1154 | "ring", 1155 | "rustls-pki-types", 1156 | "rustls-webpki", 1157 | "subtle", 1158 | "zeroize", 1159 | ] 1160 | 1161 | [[package]] 1162 | name = "rustls-pki-types" 1163 | version = "1.12.0" 1164 | source = "registry+https://github.com/rust-lang/crates.io-index" 1165 | checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" 1166 | dependencies = [ 1167 | "zeroize", 1168 | ] 1169 | 1170 | [[package]] 1171 | name = "rustls-webpki" 1172 | version = "0.103.3" 1173 | source = "registry+https://github.com/rust-lang/crates.io-index" 1174 | checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" 1175 | dependencies = [ 1176 | "ring", 1177 | "rustls-pki-types", 1178 | "untrusted", 1179 | ] 1180 | 1181 | [[package]] 1182 | name = "rusty-fork" 1183 | version = "0.3.0" 1184 | source = "registry+https://github.com/rust-lang/crates.io-index" 1185 | checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" 1186 | dependencies = [ 1187 | "fnv", 1188 | "quick-error", 1189 | "tempfile", 1190 | "wait-timeout", 1191 | ] 1192 | 1193 | [[package]] 1194 | name = "ryu" 1195 | version = "1.0.20" 1196 | source = "registry+https://github.com/rust-lang/crates.io-index" 1197 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 1198 | 1199 | [[package]] 1200 | name = "schemars" 1201 | version = "0.8.22" 1202 | source = "registry+https://github.com/rust-lang/crates.io-index" 1203 | checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" 1204 | dependencies = [ 1205 | "dyn-clone", 1206 | "serde", 1207 | "serde_json", 1208 | ] 1209 | 1210 | [[package]] 1211 | name = "schemars" 1212 | version = "0.9.0" 1213 | source = "registry+https://github.com/rust-lang/crates.io-index" 1214 | checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" 1215 | dependencies = [ 1216 | "dyn-clone", 1217 | "ref-cast", 1218 | "serde", 1219 | "serde_json", 1220 | ] 1221 | 1222 | [[package]] 1223 | name = "schemars" 1224 | version = "1.0.0" 1225 | source = "registry+https://github.com/rust-lang/crates.io-index" 1226 | checksum = "febc07c7e70b5db4f023485653c754d76e1bbe8d9dbfa20193ce13da9f9633f4" 1227 | dependencies = [ 1228 | "dyn-clone", 1229 | "ref-cast", 1230 | "serde", 1231 | "serde_json", 1232 | ] 1233 | 1234 | [[package]] 1235 | name = "scopeguard" 1236 | version = "1.2.0" 1237 | source = "registry+https://github.com/rust-lang/crates.io-index" 1238 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1239 | 1240 | [[package]] 1241 | name = "scraper" 1242 | version = "0.19.1" 1243 | source = "registry+https://github.com/rust-lang/crates.io-index" 1244 | checksum = "761fb705fdf625482d2ed91d3f0559dcfeab2798fe2771c69560a774865d0802" 1245 | dependencies = [ 1246 | "ahash", 1247 | "cssparser", 1248 | "ego-tree", 1249 | "getopts", 1250 | "html5ever", 1251 | "once_cell", 1252 | "selectors", 1253 | "tendril", 1254 | ] 1255 | 1256 | [[package]] 1257 | name = "selectors" 1258 | version = "0.25.0" 1259 | source = "registry+https://github.com/rust-lang/crates.io-index" 1260 | checksum = "4eb30575f3638fc8f6815f448d50cb1a2e255b0897985c8c59f4d37b72a07b06" 1261 | dependencies = [ 1262 | "bitflags", 1263 | "cssparser", 1264 | "derive_more", 1265 | "fxhash", 1266 | "log", 1267 | "new_debug_unreachable", 1268 | "phf 0.10.1", 1269 | "phf_codegen 0.10.0", 1270 | "precomputed-hash", 1271 | "servo_arc", 1272 | "smallvec", 1273 | ] 1274 | 1275 | [[package]] 1276 | name = "serde" 1277 | version = "1.0.219" 1278 | source = "registry+https://github.com/rust-lang/crates.io-index" 1279 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 1280 | dependencies = [ 1281 | "serde_derive", 1282 | ] 1283 | 1284 | [[package]] 1285 | name = "serde_derive" 1286 | version = "1.0.219" 1287 | source = "registry+https://github.com/rust-lang/crates.io-index" 1288 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 1289 | dependencies = [ 1290 | "proc-macro2", 1291 | "quote", 1292 | "syn", 1293 | ] 1294 | 1295 | [[package]] 1296 | name = "serde_json" 1297 | version = "1.0.140" 1298 | source = "registry+https://github.com/rust-lang/crates.io-index" 1299 | checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" 1300 | dependencies = [ 1301 | "itoa", 1302 | "memchr", 1303 | "ryu", 1304 | "serde", 1305 | ] 1306 | 1307 | [[package]] 1308 | name = "servo_arc" 1309 | version = "0.3.0" 1310 | source = "registry+https://github.com/rust-lang/crates.io-index" 1311 | checksum = "d036d71a959e00c77a63538b90a6c2390969f9772b096ea837205c6bd0491a44" 1312 | dependencies = [ 1313 | "stable_deref_trait", 1314 | ] 1315 | 1316 | [[package]] 1317 | name = "shlex" 1318 | version = "1.3.0" 1319 | source = "registry+https://github.com/rust-lang/crates.io-index" 1320 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1321 | 1322 | [[package]] 1323 | name = "siphasher" 1324 | version = "0.3.11" 1325 | source = "registry+https://github.com/rust-lang/crates.io-index" 1326 | checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" 1327 | 1328 | [[package]] 1329 | name = "siphasher" 1330 | version = "1.0.1" 1331 | source = "registry+https://github.com/rust-lang/crates.io-index" 1332 | checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" 1333 | 1334 | [[package]] 1335 | name = "smallvec" 1336 | version = "1.15.1" 1337 | source = "registry+https://github.com/rust-lang/crates.io-index" 1338 | checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 1339 | 1340 | [[package]] 1341 | name = "stable_deref_trait" 1342 | version = "1.2.0" 1343 | source = "registry+https://github.com/rust-lang/crates.io-index" 1344 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1345 | 1346 | [[package]] 1347 | name = "string_cache" 1348 | version = "0.8.9" 1349 | source = "registry+https://github.com/rust-lang/crates.io-index" 1350 | checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" 1351 | dependencies = [ 1352 | "new_debug_unreachable", 1353 | "parking_lot", 1354 | "phf_shared 0.11.3", 1355 | "precomputed-hash", 1356 | "serde", 1357 | ] 1358 | 1359 | [[package]] 1360 | name = "string_cache_codegen" 1361 | version = "0.5.4" 1362 | source = "registry+https://github.com/rust-lang/crates.io-index" 1363 | checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" 1364 | dependencies = [ 1365 | "phf_generator 0.11.3", 1366 | "phf_shared 0.11.3", 1367 | "proc-macro2", 1368 | "quote", 1369 | ] 1370 | 1371 | [[package]] 1372 | name = "strsim" 1373 | version = "0.11.1" 1374 | source = "registry+https://github.com/rust-lang/crates.io-index" 1375 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1376 | 1377 | [[package]] 1378 | name = "subtle" 1379 | version = "2.6.1" 1380 | source = "registry+https://github.com/rust-lang/crates.io-index" 1381 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1382 | 1383 | [[package]] 1384 | name = "supports-color" 1385 | version = "3.0.2" 1386 | source = "registry+https://github.com/rust-lang/crates.io-index" 1387 | checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6" 1388 | dependencies = [ 1389 | "is_ci", 1390 | ] 1391 | 1392 | [[package]] 1393 | name = "supports-hyperlinks" 1394 | version = "3.1.0" 1395 | source = "registry+https://github.com/rust-lang/crates.io-index" 1396 | checksum = "804f44ed3c63152de6a9f90acbea1a110441de43006ea51bcce8f436196a288b" 1397 | 1398 | [[package]] 1399 | name = "supports-unicode" 1400 | version = "3.0.0" 1401 | source = "registry+https://github.com/rust-lang/crates.io-index" 1402 | checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" 1403 | 1404 | [[package]] 1405 | name = "syn" 1406 | version = "2.0.104" 1407 | source = "registry+https://github.com/rust-lang/crates.io-index" 1408 | checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" 1409 | dependencies = [ 1410 | "proc-macro2", 1411 | "quote", 1412 | "unicode-ident", 1413 | ] 1414 | 1415 | [[package]] 1416 | name = "syn-miette" 1417 | version = "0.3.0" 1418 | source = "registry+https://github.com/rust-lang/crates.io-index" 1419 | checksum = "dd1a2bfae2df81406f8d21baa0253d34ddd0ddafcd1e7aa12aa24279bb76a24b" 1420 | dependencies = [ 1421 | "miette", 1422 | "proc-macro2", 1423 | "syn", 1424 | ] 1425 | 1426 | [[package]] 1427 | name = "synstructure" 1428 | version = "0.13.2" 1429 | source = "registry+https://github.com/rust-lang/crates.io-index" 1430 | checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" 1431 | dependencies = [ 1432 | "proc-macro2", 1433 | "quote", 1434 | "syn", 1435 | ] 1436 | 1437 | [[package]] 1438 | name = "tempfile" 1439 | version = "3.20.0" 1440 | source = "registry+https://github.com/rust-lang/crates.io-index" 1441 | checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" 1442 | dependencies = [ 1443 | "fastrand", 1444 | "getrandom 0.3.3", 1445 | "once_cell", 1446 | "rustix", 1447 | "windows-sys 0.59.0", 1448 | ] 1449 | 1450 | [[package]] 1451 | name = "tendril" 1452 | version = "0.4.3" 1453 | source = "registry+https://github.com/rust-lang/crates.io-index" 1454 | checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" 1455 | dependencies = [ 1456 | "futf", 1457 | "mac", 1458 | "utf-8", 1459 | ] 1460 | 1461 | [[package]] 1462 | name = "terminal_size" 1463 | version = "0.4.2" 1464 | source = "registry+https://github.com/rust-lang/crates.io-index" 1465 | checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" 1466 | dependencies = [ 1467 | "rustix", 1468 | "windows-sys 0.59.0", 1469 | ] 1470 | 1471 | [[package]] 1472 | name = "textwrap" 1473 | version = "0.16.2" 1474 | source = "registry+https://github.com/rust-lang/crates.io-index" 1475 | checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" 1476 | dependencies = [ 1477 | "unicode-linebreak", 1478 | "unicode-width 0.2.1", 1479 | ] 1480 | 1481 | [[package]] 1482 | name = "tinystr" 1483 | version = "0.8.1" 1484 | source = "registry+https://github.com/rust-lang/crates.io-index" 1485 | checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" 1486 | dependencies = [ 1487 | "displaydoc", 1488 | "zerovec", 1489 | ] 1490 | 1491 | [[package]] 1492 | name = "unarray" 1493 | version = "0.1.4" 1494 | source = "registry+https://github.com/rust-lang/crates.io-index" 1495 | checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" 1496 | 1497 | [[package]] 1498 | name = "unicode-ident" 1499 | version = "1.0.18" 1500 | source = "registry+https://github.com/rust-lang/crates.io-index" 1501 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 1502 | 1503 | [[package]] 1504 | name = "unicode-linebreak" 1505 | version = "0.1.5" 1506 | source = "registry+https://github.com/rust-lang/crates.io-index" 1507 | checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" 1508 | 1509 | [[package]] 1510 | name = "unicode-width" 1511 | version = "0.1.14" 1512 | source = "registry+https://github.com/rust-lang/crates.io-index" 1513 | checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 1514 | 1515 | [[package]] 1516 | name = "unicode-width" 1517 | version = "0.2.1" 1518 | source = "registry+https://github.com/rust-lang/crates.io-index" 1519 | checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" 1520 | 1521 | [[package]] 1522 | name = "untrusted" 1523 | version = "0.9.0" 1524 | source = "registry+https://github.com/rust-lang/crates.io-index" 1525 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1526 | 1527 | [[package]] 1528 | name = "ureq" 1529 | version = "2.12.1" 1530 | source = "registry+https://github.com/rust-lang/crates.io-index" 1531 | checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" 1532 | dependencies = [ 1533 | "base64", 1534 | "flate2", 1535 | "log", 1536 | "once_cell", 1537 | "rustls", 1538 | "rustls-pki-types", 1539 | "url", 1540 | "webpki-roots 0.26.11", 1541 | ] 1542 | 1543 | [[package]] 1544 | name = "url" 1545 | version = "2.5.4" 1546 | source = "registry+https://github.com/rust-lang/crates.io-index" 1547 | checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 1548 | dependencies = [ 1549 | "form_urlencoded", 1550 | "idna", 1551 | "percent-encoding", 1552 | ] 1553 | 1554 | [[package]] 1555 | name = "utf-8" 1556 | version = "0.7.6" 1557 | source = "registry+https://github.com/rust-lang/crates.io-index" 1558 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 1559 | 1560 | [[package]] 1561 | name = "utf8_iter" 1562 | version = "1.0.4" 1563 | source = "registry+https://github.com/rust-lang/crates.io-index" 1564 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 1565 | 1566 | [[package]] 1567 | name = "utf8parse" 1568 | version = "0.2.2" 1569 | source = "registry+https://github.com/rust-lang/crates.io-index" 1570 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 1571 | 1572 | [[package]] 1573 | name = "version_check" 1574 | version = "0.9.5" 1575 | source = "registry+https://github.com/rust-lang/crates.io-index" 1576 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1577 | 1578 | [[package]] 1579 | name = "wait-timeout" 1580 | version = "0.2.1" 1581 | source = "registry+https://github.com/rust-lang/crates.io-index" 1582 | checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" 1583 | dependencies = [ 1584 | "libc", 1585 | ] 1586 | 1587 | [[package]] 1588 | name = "wasi" 1589 | version = "0.11.1+wasi-snapshot-preview1" 1590 | source = "registry+https://github.com/rust-lang/crates.io-index" 1591 | checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 1592 | 1593 | [[package]] 1594 | name = "wasi" 1595 | version = "0.14.2+wasi-0.2.4" 1596 | source = "registry+https://github.com/rust-lang/crates.io-index" 1597 | checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" 1598 | dependencies = [ 1599 | "wit-bindgen-rt", 1600 | ] 1601 | 1602 | [[package]] 1603 | name = "webpki-roots" 1604 | version = "0.26.11" 1605 | source = "registry+https://github.com/rust-lang/crates.io-index" 1606 | checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" 1607 | dependencies = [ 1608 | "webpki-roots 1.0.1", 1609 | ] 1610 | 1611 | [[package]] 1612 | name = "webpki-roots" 1613 | version = "1.0.1" 1614 | source = "registry+https://github.com/rust-lang/crates.io-index" 1615 | checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502" 1616 | dependencies = [ 1617 | "rustls-pki-types", 1618 | ] 1619 | 1620 | [[package]] 1621 | name = "windows-sys" 1622 | version = "0.52.0" 1623 | source = "registry+https://github.com/rust-lang/crates.io-index" 1624 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1625 | dependencies = [ 1626 | "windows-targets 0.52.6", 1627 | ] 1628 | 1629 | [[package]] 1630 | name = "windows-sys" 1631 | version = "0.59.0" 1632 | source = "registry+https://github.com/rust-lang/crates.io-index" 1633 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1634 | dependencies = [ 1635 | "windows-targets 0.52.6", 1636 | ] 1637 | 1638 | [[package]] 1639 | name = "windows-sys" 1640 | version = "0.60.2" 1641 | source = "registry+https://github.com/rust-lang/crates.io-index" 1642 | checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 1643 | dependencies = [ 1644 | "windows-targets 0.53.2", 1645 | ] 1646 | 1647 | [[package]] 1648 | name = "windows-targets" 1649 | version = "0.52.6" 1650 | source = "registry+https://github.com/rust-lang/crates.io-index" 1651 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1652 | dependencies = [ 1653 | "windows_aarch64_gnullvm 0.52.6", 1654 | "windows_aarch64_msvc 0.52.6", 1655 | "windows_i686_gnu 0.52.6", 1656 | "windows_i686_gnullvm 0.52.6", 1657 | "windows_i686_msvc 0.52.6", 1658 | "windows_x86_64_gnu 0.52.6", 1659 | "windows_x86_64_gnullvm 0.52.6", 1660 | "windows_x86_64_msvc 0.52.6", 1661 | ] 1662 | 1663 | [[package]] 1664 | name = "windows-targets" 1665 | version = "0.53.2" 1666 | source = "registry+https://github.com/rust-lang/crates.io-index" 1667 | checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" 1668 | dependencies = [ 1669 | "windows_aarch64_gnullvm 0.53.0", 1670 | "windows_aarch64_msvc 0.53.0", 1671 | "windows_i686_gnu 0.53.0", 1672 | "windows_i686_gnullvm 0.53.0", 1673 | "windows_i686_msvc 0.53.0", 1674 | "windows_x86_64_gnu 0.53.0", 1675 | "windows_x86_64_gnullvm 0.53.0", 1676 | "windows_x86_64_msvc 0.53.0", 1677 | ] 1678 | 1679 | [[package]] 1680 | name = "windows_aarch64_gnullvm" 1681 | version = "0.52.6" 1682 | source = "registry+https://github.com/rust-lang/crates.io-index" 1683 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1684 | 1685 | [[package]] 1686 | name = "windows_aarch64_gnullvm" 1687 | version = "0.53.0" 1688 | source = "registry+https://github.com/rust-lang/crates.io-index" 1689 | checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" 1690 | 1691 | [[package]] 1692 | name = "windows_aarch64_msvc" 1693 | version = "0.52.6" 1694 | source = "registry+https://github.com/rust-lang/crates.io-index" 1695 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1696 | 1697 | [[package]] 1698 | name = "windows_aarch64_msvc" 1699 | version = "0.53.0" 1700 | source = "registry+https://github.com/rust-lang/crates.io-index" 1701 | checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" 1702 | 1703 | [[package]] 1704 | name = "windows_i686_gnu" 1705 | version = "0.52.6" 1706 | source = "registry+https://github.com/rust-lang/crates.io-index" 1707 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1708 | 1709 | [[package]] 1710 | name = "windows_i686_gnu" 1711 | version = "0.53.0" 1712 | source = "registry+https://github.com/rust-lang/crates.io-index" 1713 | checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" 1714 | 1715 | [[package]] 1716 | name = "windows_i686_gnullvm" 1717 | version = "0.52.6" 1718 | source = "registry+https://github.com/rust-lang/crates.io-index" 1719 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1720 | 1721 | [[package]] 1722 | name = "windows_i686_gnullvm" 1723 | version = "0.53.0" 1724 | source = "registry+https://github.com/rust-lang/crates.io-index" 1725 | checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" 1726 | 1727 | [[package]] 1728 | name = "windows_i686_msvc" 1729 | version = "0.52.6" 1730 | source = "registry+https://github.com/rust-lang/crates.io-index" 1731 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1732 | 1733 | [[package]] 1734 | name = "windows_i686_msvc" 1735 | version = "0.53.0" 1736 | source = "registry+https://github.com/rust-lang/crates.io-index" 1737 | checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" 1738 | 1739 | [[package]] 1740 | name = "windows_x86_64_gnu" 1741 | version = "0.52.6" 1742 | source = "registry+https://github.com/rust-lang/crates.io-index" 1743 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1744 | 1745 | [[package]] 1746 | name = "windows_x86_64_gnu" 1747 | version = "0.53.0" 1748 | source = "registry+https://github.com/rust-lang/crates.io-index" 1749 | checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" 1750 | 1751 | [[package]] 1752 | name = "windows_x86_64_gnullvm" 1753 | version = "0.52.6" 1754 | source = "registry+https://github.com/rust-lang/crates.io-index" 1755 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1756 | 1757 | [[package]] 1758 | name = "windows_x86_64_gnullvm" 1759 | version = "0.53.0" 1760 | source = "registry+https://github.com/rust-lang/crates.io-index" 1761 | checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" 1762 | 1763 | [[package]] 1764 | name = "windows_x86_64_msvc" 1765 | version = "0.52.6" 1766 | source = "registry+https://github.com/rust-lang/crates.io-index" 1767 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1768 | 1769 | [[package]] 1770 | name = "windows_x86_64_msvc" 1771 | version = "0.53.0" 1772 | source = "registry+https://github.com/rust-lang/crates.io-index" 1773 | checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" 1774 | 1775 | [[package]] 1776 | name = "wit-bindgen-rt" 1777 | version = "0.39.0" 1778 | source = "registry+https://github.com/rust-lang/crates.io-index" 1779 | checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" 1780 | dependencies = [ 1781 | "bitflags", 1782 | ] 1783 | 1784 | [[package]] 1785 | name = "writeable" 1786 | version = "0.6.1" 1787 | source = "registry+https://github.com/rust-lang/crates.io-index" 1788 | checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" 1789 | 1790 | [[package]] 1791 | name = "yoke" 1792 | version = "0.8.0" 1793 | source = "registry+https://github.com/rust-lang/crates.io-index" 1794 | checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" 1795 | dependencies = [ 1796 | "serde", 1797 | "stable_deref_trait", 1798 | "yoke-derive", 1799 | "zerofrom", 1800 | ] 1801 | 1802 | [[package]] 1803 | name = "yoke-derive" 1804 | version = "0.8.0" 1805 | source = "registry+https://github.com/rust-lang/crates.io-index" 1806 | checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" 1807 | dependencies = [ 1808 | "proc-macro2", 1809 | "quote", 1810 | "syn", 1811 | "synstructure", 1812 | ] 1813 | 1814 | [[package]] 1815 | name = "zerocopy" 1816 | version = "0.8.26" 1817 | source = "registry+https://github.com/rust-lang/crates.io-index" 1818 | checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" 1819 | dependencies = [ 1820 | "zerocopy-derive", 1821 | ] 1822 | 1823 | [[package]] 1824 | name = "zerocopy-derive" 1825 | version = "0.8.26" 1826 | source = "registry+https://github.com/rust-lang/crates.io-index" 1827 | checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" 1828 | dependencies = [ 1829 | "proc-macro2", 1830 | "quote", 1831 | "syn", 1832 | ] 1833 | 1834 | [[package]] 1835 | name = "zerofrom" 1836 | version = "0.1.6" 1837 | source = "registry+https://github.com/rust-lang/crates.io-index" 1838 | checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 1839 | dependencies = [ 1840 | "zerofrom-derive", 1841 | ] 1842 | 1843 | [[package]] 1844 | name = "zerofrom-derive" 1845 | version = "0.1.6" 1846 | source = "registry+https://github.com/rust-lang/crates.io-index" 1847 | checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 1848 | dependencies = [ 1849 | "proc-macro2", 1850 | "quote", 1851 | "syn", 1852 | "synstructure", 1853 | ] 1854 | 1855 | [[package]] 1856 | name = "zeroize" 1857 | version = "1.8.1" 1858 | source = "registry+https://github.com/rust-lang/crates.io-index" 1859 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 1860 | 1861 | [[package]] 1862 | name = "zerotrie" 1863 | version = "0.2.2" 1864 | source = "registry+https://github.com/rust-lang/crates.io-index" 1865 | checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" 1866 | dependencies = [ 1867 | "displaydoc", 1868 | "yoke", 1869 | "zerofrom", 1870 | ] 1871 | 1872 | [[package]] 1873 | name = "zerovec" 1874 | version = "0.11.2" 1875 | source = "registry+https://github.com/rust-lang/crates.io-index" 1876 | checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" 1877 | dependencies = [ 1878 | "yoke", 1879 | "zerofrom", 1880 | "zerovec-derive", 1881 | ] 1882 | 1883 | [[package]] 1884 | name = "zerovec-derive" 1885 | version = "0.11.1" 1886 | source = "registry+https://github.com/rust-lang/crates.io-index" 1887 | checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" 1888 | dependencies = [ 1889 | "proc-macro2", 1890 | "quote", 1891 | "syn", 1892 | ] 1893 | --------------------------------------------------------------------------------