From 10960f679c7b7d0558d6700857429149b1649000 Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Fri, 3 May 2024 22:16:32 +0200 Subject: [PATCH 01/25] const LEN -> type LEN --- core/Cargo.toml | 1 + core/src/hlist.rs | 43 +++++++++++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/core/Cargo.toml b/core/Cargo.toml index afc58b1b..08005d5c 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -18,6 +18,7 @@ std = [] [dependencies] serde = { version = "^1.0", optional = true, features = [ "derive" ] } +typenum = { version = "1.17.0", default-features = false } [dev-dependencies.frunk_derives] path = "../derives" diff --git a/core/src/hlist.rs b/core/src/hlist.rs index 2fdee009..3d9cb92f 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -59,6 +59,8 @@ use crate::indices::{Here, Suffixed, There}; use crate::traits::{Func, IntoReverse, Poly, ToMut, ToRef}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use typenum::bit::B1; +use typenum::{Unsigned, UInt, UTerm}; use std::ops::Add; @@ -67,8 +69,7 @@ use std::ops::Add; /// An HList is a heterogeneous list, one that is statically typed at compile time. In simple terms, /// it is just an arbitrarily-nested Tuple2. pub trait HList: Sized { - /// Returns the length of a given HList type without making use of any references, or - /// in fact, any values at all. + /// The type-level encapsulation of the lists length, using `typenum` under the hood. /// /// # Examples /// ``` @@ -76,10 +77,15 @@ pub trait HList: Sized { /// use frunk::prelude::*; /// use frunk_core::HList; /// - /// assert_eq!(::LEN, 3); + /// fn foo>() {} + /// let _ = foo::(); + /// let byte: u32 = HList![bool, &str, String]::Len::UINT32; + /// + /// + /// assert_eq!(::Len, 3); /// # } /// ``` - const LEN: usize; + type Len: Unsigned; /// Returns the length of a given HList /// @@ -93,9 +99,10 @@ pub trait HList: Sized { /// assert_eq!(h.len(), 2); /// # } /// ``` + #[deprecated(since = "0.5.0", note = "Please use Len::USIZE instead")] #[inline] fn len(&self) -> usize { - Self::LEN + ::USIZE } /// Returns whether a given HList is empty @@ -112,7 +119,7 @@ pub trait HList: Sized { /// ``` #[inline] fn is_empty(&self) -> bool { - Self::LEN == 0 + ::USIZE == 0 } /// Returns the length of a given HList type without making use of any references, or @@ -127,7 +134,7 @@ pub trait HList: Sized { /// assert_eq!(::static_len(), 3); /// # } /// ``` - #[deprecated(since = "0.1.31", note = "Please use LEN instead")] + #[deprecated(since = "0.1.31", note = "Please use Len::USIZE instead")] fn static_len() -> usize; /// Prepends an item to the current HList @@ -168,9 +175,9 @@ pub trait HList: Sized { pub struct HNil; impl HList for HNil { - const LEN: usize = 0; + type Len = typenum::U0; fn static_len() -> usize { - Self::LEN + ::USIZE } } @@ -183,10 +190,14 @@ pub struct HCons { pub tail: T, } -impl HList for HCons { - const LEN: usize = 1 + ::LEN; +impl HList for HCons +where + ::Len: Add, + <::Len as Add>::Output: Unsigned +{ + type Len = <::Len as Add>::Output; fn static_len() -> usize { - Self::LEN + ::USIZE } } @@ -1123,6 +1134,8 @@ impl HZippable for HNil { impl HZippable> for HCons where T1: HZippable, + <>::Zipped as HList>::Len: Add>, + <<>::Zipped as HList>::Len as Add>>::Output: Unsigned, { type Zipped = HCons<(H1, H2), T1::Zipped>; fn zip(self, other: HCons) -> Self::Zipped { @@ -1438,11 +1451,13 @@ where impl Into> for HCons where Tail: Into> + HList, + ::Len: Add>, + <::Len as Add>>::Output: Unsigned, { fn into(self) -> Vec { let h = self.head; let t = self.tail; - let mut v = Vec::with_capacity(::LEN); + let mut v = Vec::with_capacity(<::Len as Unsigned>::USIZE); v.push(h); let mut t_vec: Vec = t.into(); v.append(&mut t_vec); @@ -1905,7 +1920,7 @@ mod tests { #[test] fn test_len_const() { - assert_eq!(::LEN, 3); + assert_eq!(::Len::USIZE, 3); } #[test] From 56781742d190dbc6bb91f76c714f690704292e0d Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Fri, 3 May 2024 22:17:04 +0200 Subject: [PATCH 02/25] deprecate len() for Self::Len + version-bump --- Cargo.toml | 4 ++-- core/Cargo.toml | 4 ++-- laws/Cargo.toml | 2 +- proc-macro-helpers/Cargo.toml | 2 +- proc-macros/Cargo.toml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dab64399..4cf4331b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "frunk" edition = "2021" -version = "0.4.2" +version = "0.5.0" authors = ["Lloyd "] description = "Frunk provides developers with a number of functional programming tools like HList, Coproduct, Generic, LabelledGeneric, Validated, Monoid, Semigroup and friends." license = "MIT" @@ -19,7 +19,7 @@ time = "0.3" [dependencies.frunk_core] path = "core" default-features = false -version = "0.4.2" +version = "0.5.0" [dependencies.frunk_proc_macros] path = "proc-macros" diff --git a/core/Cargo.toml b/core/Cargo.toml index 08005d5c..be695e6a 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "frunk_core" edition = "2021" -version = "0.4.2" +version = "0.5.0" authors = ["Lloyd "] description = "Frunk core provides developers with HList, Coproduct, LabelledGeneric and Generic" license = "MIT" @@ -28,7 +28,7 @@ version = "0.4.1" [dev-dependencies.frunk] path = ".." default-features = false -version = "0.4.2" +version = "0.5.0" [dev-dependencies.frunk_proc_macros] path = "../proc-macros" diff --git a/laws/Cargo.toml b/laws/Cargo.toml index 576948b6..42280264 100644 --- a/laws/Cargo.toml +++ b/laws/Cargo.toml @@ -15,7 +15,7 @@ travis-ci = { repository = "lloydmeta/frunk" } [dependencies.frunk] path = ".." default-features = false -version = "0.4.2" +version = "0.5.0" [dependencies] quickcheck = "1.0.3" diff --git a/proc-macro-helpers/Cargo.toml b/proc-macro-helpers/Cargo.toml index a58542f5..67fd7558 100644 --- a/proc-macro-helpers/Cargo.toml +++ b/proc-macro-helpers/Cargo.toml @@ -20,4 +20,4 @@ proc-macro2 = "1" [dependencies.frunk_core] path = "../core" default-features = false -version = "0.4.2" +version = "0.5.0" diff --git a/proc-macros/Cargo.toml b/proc-macros/Cargo.toml index b190ef27..1c2b3070 100644 --- a/proc-macros/Cargo.toml +++ b/proc-macros/Cargo.toml @@ -23,7 +23,7 @@ proc-macro = true [dependencies.frunk_core] path = "../core" default-features = false -version = "0.4.2" +version = "0.5.0" [dependencies.frunk_proc_macro_helpers] path = "../proc-macro-helpers" From 001a667f417e7b6c84bbdd15aa91c22296b31f0b Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Fri, 3 May 2024 22:39:31 +0200 Subject: [PATCH 03/25] Correct doc-test. --- core/src/hlist.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/core/src/hlist.rs b/core/src/hlist.rs index 3d9cb92f..31a24ac5 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -74,15 +74,18 @@ pub trait HList: Sized { /// # Examples /// ``` /// # fn main() { + /// use typenum::Unsigned; /// use frunk::prelude::*; /// use frunk_core::HList; /// - /// fn foo>() {} - /// let _ = foo::(); - /// let byte: u32 = HList![bool, &str, String]::Len::UINT32; + /// type LenThree = HList![bool, (), u8]; + /// fn foo>() {} /// + /// let _ = foo::<::Len>(); + /// let byte: u8 = <::Len>::U8; /// - /// assert_eq!(::Len, 3); + /// + /// assert_eq!(::Len::USIZE, 3); /// # } /// ``` type Len: Unsigned; From bdad2d17bfe8898b073c40b58baca27174f76ce1 Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Fri, 3 May 2024 22:57:56 +0200 Subject: [PATCH 04/25] add "teaser-trailer" of using typnum internally --- core/src/hlist.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/hlist.rs b/core/src/hlist.rs index 31a24ac5..ed5859fc 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -102,7 +102,7 @@ pub trait HList: Sized { /// assert_eq!(h.len(), 2); /// # } /// ``` - #[deprecated(since = "0.5.0", note = "Please use Len::USIZE instead")] + #[deprecated(since = "0.5.0", note = "Please use ::Len::[USIZE | U8 | U32 | ... ] instead")] #[inline] fn len(&self) -> usize { ::USIZE @@ -266,6 +266,9 @@ macro_rules! gen_inherent_methods { pub fn len(&self) -> usize where Self: HList, { + // this is how it's done at the type-level + // ::Len::USIZE + #[allow(deprecated)] HList::len(self) } @@ -286,6 +289,8 @@ macro_rules! gen_inherent_methods { where Self: HList, { HList::is_empty(self) + // this is how it's done at the type-level + // <<::Len as typenum::IsEqual>::Output as typenum::Bit>::BOOL } /// Prepend an item to the current HList From a024384e5ecd63a9c6ba01f6603d98c9baeb514c Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Sat, 4 May 2024 09:23:23 +0200 Subject: [PATCH 05/25] cargo fmt --- core/src/hlist.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/core/src/hlist.rs b/core/src/hlist.rs index ed5859fc..af93d9a5 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -60,7 +60,7 @@ use crate::traits::{Func, IntoReverse, Poly, ToMut, ToRef}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use typenum::bit::B1; -use typenum::{Unsigned, UInt, UTerm}; +use typenum::{UInt, UTerm, Unsigned}; use std::ops::Add; @@ -102,7 +102,10 @@ pub trait HList: Sized { /// assert_eq!(h.len(), 2); /// # } /// ``` - #[deprecated(since = "0.5.0", note = "Please use ::Len::[USIZE | U8 | U32 | ... ] instead")] + #[deprecated( + since = "0.5.0", + note = "Please use ::Len::[USIZE | U8 | U32 | ... ] instead" + )] #[inline] fn len(&self) -> usize { ::USIZE @@ -193,10 +196,10 @@ pub struct HCons { pub tail: T, } -impl HList for HCons -where +impl HList for HCons +where ::Len: Add, - <::Len as Add>::Output: Unsigned + <::Len as Add>::Output: Unsigned, { type Len = <::Len as Add>::Output; fn static_len() -> usize { From f2ff09c2ee609be1a6c5856d0a5fedb6c6ac274d Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Sat, 4 May 2024 14:03:40 +0200 Subject: [PATCH 06/25] update length-get support --- core/src/hlist.rs | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/core/src/hlist.rs b/core/src/hlist.rs index af93d9a5..200951f0 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -102,10 +102,6 @@ pub trait HList: Sized { /// assert_eq!(h.len(), 2); /// # } /// ``` - #[deprecated( - since = "0.5.0", - note = "Please use ::Len::[USIZE | U8 | U32 | ... ] instead" - )] #[inline] fn len(&self) -> usize { ::USIZE @@ -128,21 +124,6 @@ pub trait HList: Sized { ::USIZE == 0 } - /// Returns the length of a given HList type without making use of any references, or - /// in fact, any values at all. - /// - /// # Examples - /// ``` - /// # fn main() { - /// use frunk::prelude::*; - /// use frunk_core::HList; - /// - /// assert_eq!(::static_len(), 3); - /// # } - /// ``` - #[deprecated(since = "0.1.31", note = "Please use Len::USIZE instead")] - fn static_len() -> usize; - /// Prepends an item to the current HList /// /// # Examples @@ -182,9 +163,6 @@ pub struct HNil; impl HList for HNil { type Len = typenum::U0; - fn static_len() -> usize { - ::USIZE - } } /// Represents the most basic non-empty HList. Its value is held in `head` @@ -202,9 +180,6 @@ where <::Len as Add>::Output: Unsigned, { type Len = <::Len as Add>::Output; - fn static_len() -> usize { - ::USIZE - } } impl HCons { From 91f4442ac087ee5bbd0fc85b1e42540403d8c8ea Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Sat, 4 May 2024 14:10:41 +0200 Subject: [PATCH 07/25] retain the const-generic --- core/src/hlist.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/src/hlist.rs b/core/src/hlist.rs index 200951f0..3fd4896f 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -90,6 +90,8 @@ pub trait HList: Sized { /// ``` type Len: Unsigned; + const LEN: usize; + /// Returns the length of a given HList /// /// # Examples @@ -163,6 +165,8 @@ pub struct HNil; impl HList for HNil { type Len = typenum::U0; + + const LEN: usize = 0; } /// Represents the most basic non-empty HList. Its value is held in `head` @@ -180,6 +184,8 @@ where <::Len as Add>::Output: Unsigned, { type Len = <::Len as Add>::Output; + + const LEN: usize = 0; } impl HCons { From e0783fcf814dd744ff06fcc14d9aa3427bdb6f21 Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Sat, 4 May 2024 14:27:00 +0200 Subject: [PATCH 08/25] Refine doc-comments. --- core/src/hlist.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/core/src/hlist.rs b/core/src/hlist.rs index 3fd4896f..fb68f374 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -62,6 +62,7 @@ use serde::{Deserialize, Serialize}; use typenum::bit::B1; use typenum::{UInt, UTerm, Unsigned}; + use std::ops::Add; /// Typeclass for HList-y behaviour @@ -74,22 +75,35 @@ pub trait HList: Sized { /// # Examples /// ``` /// # fn main() { - /// use typenum::Unsigned; + /// use frunk_core::typenum::Unsigned; /// use frunk::prelude::*; /// use frunk_core::HList; /// /// type LenThree = HList![bool, (), u8]; - /// fn foo>() {} + /// type LenTwo = HList![bool, ()]; + /// + /// // Attach a constraint that ensures constraints are met at type-check time + /// fn type_len_constraint>() {} + /// /// - /// let _ = foo::<::Len>(); + /// + /// // Won't compile: the length of LenThree doesn't meet the less-than-3 requirement + /// // let _ = type_len_constraint::<::Len>(); + /// + /// // ...this works, though + /// let _ = type_len_constraint::<::Len>(); + /// + /// // Pull out the length of the list in the word-size of your choosing. /// let byte: u8 = <::Len>::U8; + /// let u_16: u16 = <::Len>::U16; /// /// - /// assert_eq!(::Len::USIZE, 3); + /// assert_eq!(::Len::U8, 3u8); /// # } /// ``` type Len: Unsigned; + /// Length as a usize const generic. Is equivilent to `::LEN::USIZE` const LEN: usize; /// Returns the length of a given HList @@ -184,7 +198,6 @@ where <::Len as Add>::Output: Unsigned, { type Len = <::Len as Add>::Output; - const LEN: usize = 0; } From b1521ae8e7db4b5844b6a7e0c0e824ba626e0896 Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Sat, 4 May 2024 19:04:00 +0200 Subject: [PATCH 09/25] Clean some things up --- core/src/hlist.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/core/src/hlist.rs b/core/src/hlist.rs index fb68f374..998f877d 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -59,8 +59,9 @@ use crate::indices::{Here, Suffixed, There}; use crate::traits::{Func, IntoReverse, Poly, ToMut, ToRef}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use typenum::bit::B1; -use typenum::{UInt, UTerm, Unsigned}; + +use typenum::{Add1, bit::B1, Unsigned}; +pub use typenum; use std::ops::Add; @@ -75,7 +76,7 @@ pub trait HList: Sized { /// # Examples /// ``` /// # fn main() { - /// use frunk_core::typenum::Unsigned; + /// use frunk_core::hlist::typenum::Unsigned; /// use frunk::prelude::*; /// use frunk_core::HList; /// @@ -83,7 +84,7 @@ pub trait HList: Sized { /// type LenTwo = HList![bool, ()]; /// /// // Attach a constraint that ensures constraints are met at type-check time - /// fn type_len_constraint>() {} + /// fn type_len_constraint>() {} /// /// /// @@ -194,10 +195,10 @@ pub struct HCons { impl HList for HCons where - ::Len: Add, - <::Len as Add>::Output: Unsigned, + ::Len: Add, + Add1<::Len>: Unsigned, { - type Len = <::Len as Add>::Output; + type Len = Add1<::Len>; const LEN: usize = 0; } @@ -1139,8 +1140,8 @@ impl HZippable for HNil { impl HZippable> for HCons where T1: HZippable, - <>::Zipped as HList>::Len: Add>, - <<>::Zipped as HList>::Len as Add>>::Output: Unsigned, + <>::Zipped as HList>::Len: Add, + Add1<<>::Zipped as HList>::Len>: Unsigned, { type Zipped = HCons<(H1, H2), T1::Zipped>; fn zip(self, other: HCons) -> Self::Zipped { @@ -1456,8 +1457,8 @@ where impl Into> for HCons where Tail: Into> + HList, - ::Len: Add>, - <::Len as Add>>::Output: Unsigned, + ::Len: Add, + Add1<::Len>: Unsigned, { fn into(self) -> Vec { let h = self.head; From 053516a7bad0fdd56993ba162ef87d47bd63265a Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Sat, 4 May 2024 19:04:21 +0200 Subject: [PATCH 10/25] cargo fmt --- core/src/hlist.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/src/hlist.rs b/core/src/hlist.rs index 998f877d..3a4b9834 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -60,9 +60,8 @@ use crate::traits::{Func, IntoReverse, Poly, ToMut, ToRef}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use typenum::{Add1, bit::B1, Unsigned}; pub use typenum; - +use typenum::{bit::B1, Add1, Unsigned}; use std::ops::Add; @@ -87,7 +86,7 @@ pub trait HList: Sized { /// fn type_len_constraint>() {} /// /// - /// + /// /// // Won't compile: the length of LenThree doesn't meet the less-than-3 requirement /// // let _ = type_len_constraint::<::Len>(); /// From 327efd15c9b71f68e9b2754a5f986d863b6e200f Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Sat, 4 May 2024 19:49:39 +0200 Subject: [PATCH 11/25] fix obo error --- core/src/hlist.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/hlist.rs b/core/src/hlist.rs index 3a4b9834..19ebaa2b 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -193,12 +193,12 @@ pub struct HCons { } impl HList for HCons -where +where ::Len: Add, - Add1<::Len>: Unsigned, + <::Len as Add>::Output: Unsigned { - type Len = Add1<::Len>; - const LEN: usize = 0; + type Len = <::Len as Add>::Output; + const LEN: usize = 1 + ::LEN; } impl HCons { From e3995ca6021f318ddf81307a6492f606de1266eb Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Sat, 4 May 2024 19:51:04 +0200 Subject: [PATCH 12/25] Use Self::LEN internally --- core/src/hlist.rs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/core/src/hlist.rs b/core/src/hlist.rs index 19ebaa2b..8cb7101f 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -61,7 +61,7 @@ use crate::traits::{Func, IntoReverse, Poly, ToMut, ToRef}; use serde::{Deserialize, Serialize}; pub use typenum; -use typenum::{bit::B1, Add1, Unsigned}; +use typenum::{U0, bit::B1, Add1, Unsigned}; use std::ops::Add; @@ -120,7 +120,7 @@ pub trait HList: Sized { /// ``` #[inline] fn len(&self) -> usize { - ::USIZE + Self::LEN } /// Returns whether a given HList is empty @@ -137,7 +137,7 @@ pub trait HList: Sized { /// ``` #[inline] fn is_empty(&self) -> bool { - ::USIZE == 0 + Self::LEN == 0 } /// Prepends an item to the current HList @@ -178,7 +178,7 @@ pub trait HList: Sized { pub struct HNil; impl HList for HNil { - type Len = typenum::U0; + type Len = U0; const LEN: usize = 0; } @@ -1136,6 +1136,22 @@ impl HZippable for HNil { } } +//#[cfg(feature = "typenum")] +//impl HZippable> for HCons +//where +// T1: HZippable, +// <>::Zipped as HList>::Len: Add, +// Add1<<>::Zipped as HList>::Len>: Unsigned, +//{ +// type Zipped = HCons<(H1, H2), T1::Zipped>; +// fn zip(self, other: HCons) -> Self::Zipped { +// HCons { +// head: (self.head, other.head), +// tail: self.tail.zip(other.tail), +// } +// } +//} +// #[cfg(not(feature = "typenum"))] impl HZippable> for HCons where T1: HZippable, @@ -1457,12 +1473,12 @@ impl Into> for HCons where Tail: Into> + HList, ::Len: Add, - Add1<::Len>: Unsigned, + Add1<::Len>: Unsigned { fn into(self) -> Vec { let h = self.head; let t = self.tail; - let mut v = Vec::with_capacity(<::Len as Unsigned>::USIZE); + let mut v = Vec::with_capacity(::LEN); v.push(h); let mut t_vec: Vec = t.into(); v.append(&mut t_vec); @@ -1925,7 +1941,9 @@ mod tests { #[test] fn test_len_const() { + // #[cfg(feature = "typenum")] assert_eq!(::Len::USIZE, 3); + assert_eq!(::LEN, 3); } #[test] From cb668a90731587e38c0b1ce419a74b4569cf5745 Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Sat, 4 May 2024 20:06:18 +0200 Subject: [PATCH 13/25] hide the use of typenum behind feature gate --- core/Cargo.toml | 3 ++- core/src/hlist.rs | 44 +++++++++++++++++++++++++------------------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/core/Cargo.toml b/core/Cargo.toml index be695e6a..e88d8923 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -15,10 +15,11 @@ travis-ci = { repository = "lloydmeta/frunk" } [features] default = ["std"] std = [] +typenum = ["dep:typenum"] [dependencies] serde = { version = "^1.0", optional = true, features = [ "derive" ] } -typenum = { version = "1.17.0", default-features = false } +typenum = { version = "1.17.0", optional = true, default-features = false, features = ["no_std"] } [dev-dependencies.frunk_derives] path = "../derives" diff --git a/core/src/hlist.rs b/core/src/hlist.rs index 8cb7101f..e2d1c072 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -60,7 +60,9 @@ use crate::traits::{Func, IntoReverse, Poly, ToMut, ToRef}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +#[cfg(feature = "typenum")] pub use typenum; +#[cfg(feature = "typenum")] use typenum::{U0, bit::B1, Add1, Unsigned}; use std::ops::Add; @@ -101,6 +103,7 @@ pub trait HList: Sized { /// assert_eq!(::Len::U8, 3u8); /// # } /// ``` + #[cfg(feature = "typenum")] type Len: Unsigned; /// Length as a usize const generic. Is equivilent to `::LEN::USIZE` @@ -178,6 +181,7 @@ pub trait HList: Sized { pub struct HNil; impl HList for HNil { + #[cfg(feature = "typenum")] type Len = U0; const LEN: usize = 0; @@ -192,6 +196,7 @@ pub struct HCons { pub tail: T, } +#[cfg(feature = "typenum")] impl HList for HCons where ::Len: Add, @@ -200,6 +205,11 @@ where type Len = <::Len as Add>::Output; const LEN: usize = 1 + ::LEN; } +#[cfg(not(feature = "typenum"))] +impl HList for HCons +{ + const LEN: usize = 1 + ::LEN; +} impl HCons { /// Returns the head of the list and the tail of the list as a tuple2. @@ -1136,22 +1146,20 @@ impl HZippable for HNil { } } -//#[cfg(feature = "typenum")] -//impl HZippable> for HCons -//where -// T1: HZippable, -// <>::Zipped as HList>::Len: Add, -// Add1<<>::Zipped as HList>::Len>: Unsigned, -//{ -// type Zipped = HCons<(H1, H2), T1::Zipped>; -// fn zip(self, other: HCons) -> Self::Zipped { -// HCons { -// head: (self.head, other.head), -// tail: self.tail.zip(other.tail), -// } -// } -//} -// #[cfg(not(feature = "typenum"))] +#[cfg(not(feature = "typenum"))] +impl HZippable> for HCons +where + T1: HZippable, +{ + type Zipped = HCons<(H1, H2), T1::Zipped>; + fn zip(self, other: HCons) -> Self::Zipped { + HCons { + head: (self.head, other.head), + tail: self.tail.zip(other.tail), + } + } +} +#[cfg(feature = "typenum")] impl HZippable> for HCons where T1: HZippable, @@ -1472,8 +1480,6 @@ where impl Into> for HCons where Tail: Into> + HList, - ::Len: Add, - Add1<::Len>: Unsigned { fn into(self) -> Vec { let h = self.head; @@ -1941,7 +1947,7 @@ mod tests { #[test] fn test_len_const() { - // #[cfg(feature = "typenum")] + #[cfg(feature = "typenum")] assert_eq!(::Len::USIZE, 3); assert_eq!(::LEN, 3); } From 56484d5b61d93de4060baf0e48fea5c3b353f2c5 Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Sat, 4 May 2024 20:13:10 +0200 Subject: [PATCH 14/25] In root, `cargo test --all` pass with/without typenum --- core/src/hlist.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/core/src/hlist.rs b/core/src/hlist.rs index e2d1c072..688f44a5 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -1475,12 +1475,34 @@ where } } +#[cfg(feature = "typenum")] #[cfg(feature = "std")] #[allow(clippy::from_over_into)] impl Into> for HCons where Tail: Into> + HList, + ::Len: Add, + Add1<::Len>: Unsigned { + + fn into(self) -> Vec { + let h = self.head; + let t = self.tail; + let mut v = Vec::with_capacity(::LEN); + v.push(h); + let mut t_vec: Vec = t.into(); + v.append(&mut t_vec); + v + } +} +#[cfg(not(feature = "typenum"))] +#[cfg(feature = "std")] +#[allow(clippy::from_over_into)] +impl Into> for HCons +where + Tail: Into> + HList, +{ + fn into(self) -> Vec { let h = self.head; let t = self.tail; From 8f83135b29d9533bf6207d524cbfa44b7aa054de Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Sat, 4 May 2024 20:13:24 +0200 Subject: [PATCH 15/25] cargo fmt --- core/src/hlist.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/core/src/hlist.rs b/core/src/hlist.rs index 688f44a5..cc1455b2 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -63,7 +63,7 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "typenum")] pub use typenum; #[cfg(feature = "typenum")] -use typenum::{U0, bit::B1, Add1, Unsigned}; +use typenum::{bit::B1, Add1, Unsigned, U0}; use std::ops::Add; @@ -198,16 +198,15 @@ pub struct HCons { #[cfg(feature = "typenum")] impl HList for HCons -where +where ::Len: Add, - <::Len as Add>::Output: Unsigned + <::Len as Add>::Output: Unsigned, { type Len = <::Len as Add>::Output; const LEN: usize = 1 + ::LEN; } #[cfg(not(feature = "typenum"))] -impl HList for HCons -{ +impl HList for HCons { const LEN: usize = 1 + ::LEN; } @@ -1482,10 +1481,9 @@ impl Into> for HCons where Tail: Into> + HList, ::Len: Add, - Add1<::Len>: Unsigned + Add1<::Len>: Unsigned, { - - fn into(self) -> Vec { + fn into(self) -> Vec { let h = self.head; let t = self.tail; let mut v = Vec::with_capacity(::LEN); @@ -1502,7 +1500,6 @@ impl Into> for HCons where Tail: Into> + HList, { - fn into(self) -> Vec { let h = self.head; let t = self.tail; From 8d687fe260bd9be338c09c81e6691d7300666245 Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Sat, 4 May 2024 21:41:59 +0200 Subject: [PATCH 16/25] Render feature-gate in built docs --- core/Cargo.toml | 1 + core/src/hlist.rs | 9 ++++----- core/src/lib.rs | 7 ++++++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/core/Cargo.toml b/core/Cargo.toml index e88d8923..8b6b7a82 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -16,6 +16,7 @@ travis-ci = { repository = "lloydmeta/frunk" } default = ["std"] std = [] typenum = ["dep:typenum"] +nightly = [] [dependencies] serde = { version = "^1.0", optional = true, features = [ "derive" ] } diff --git a/core/src/hlist.rs b/core/src/hlist.rs index cc1455b2..6e2f6fe9 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -60,6 +60,7 @@ use crate::traits::{Func, IntoReverse, Poly, ToMut, ToRef}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +#[doc(cfg(feature = "typenum"))] #[cfg(feature = "typenum")] pub use typenum; #[cfg(feature = "typenum")] @@ -72,6 +73,7 @@ use std::ops::Add; /// An HList is a heterogeneous list, one that is statically typed at compile time. In simple terms, /// it is just an arbitrarily-nested Tuple2. pub trait HList: Sized { + #[doc(cfg(feature = "typenum"))] /// The type-level encapsulation of the lists length, using `typenum` under the hood. /// /// # Examples @@ -272,9 +274,6 @@ macro_rules! gen_inherent_methods { pub fn len(&self) -> usize where Self: HList, { - // this is how it's done at the type-level - // ::Len::USIZE - #[allow(deprecated)] HList::len(self) } @@ -295,8 +294,6 @@ macro_rules! gen_inherent_methods { where Self: HList, { HList::is_empty(self) - // this is how it's done at the type-level - // <<::Len as typenum::IsEqual>::Output as typenum::Bit>::BOOL } /// Prepend an item to the current HList @@ -1474,6 +1471,7 @@ where } } +#[cfg_attr(feature = "nightly", doc(cfg(feature = "std")))] #[cfg(feature = "typenum")] #[cfg(feature = "std")] #[allow(clippy::from_over_into)] @@ -1494,6 +1492,7 @@ where } } #[cfg(not(feature = "typenum"))] +#[cfg_attr(feature = "nightly", doc(cfg(feature = "std")))] #[cfg(feature = "std")] #[allow(clippy::from_over_into)] impl Into> for HCons diff --git a/core/src/lib.rs b/core/src/lib.rs index bc16035f..38b7c057 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,4 +1,9 @@ -#![cfg_attr(not(feature = "std"), no_std)] +// This feature allows `cargo +nightly doc --F $GATED_FEATURES` to include +// said features as well as show that they are behind a feature gate, like so: +// #[doc(cfg(feature = "$GATED_FEATURE"))] +// ...without adding nightly requirement to non-doc builds +#![cfg_attr(feature = "nightly", feature(doc_cfg))] + #![doc(html_playground_url = "https://play.rust-lang.org/")] //! Frunk Core //! From 6a86de848259dd89ee3922b7ccfc7f3e2f433727 Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Sat, 4 May 2024 21:43:36 +0200 Subject: [PATCH 17/25] modify doc-publish to build (just docs) with nightly --- .github/workflows/rustdoc.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rustdoc.yml b/.github/workflows/rustdoc.yml index f61a8ab5..1b3fc367 100644 --- a/.github/workflows/rustdoc.yml +++ b/.github/workflows/rustdoc.yml @@ -15,7 +15,7 @@ jobs: - uses: actions-rs/toolchain@v1 with: - toolchain: stable + toolchain: nightly override: true - uses: Swatinem/rust-cache@v2 @@ -23,8 +23,8 @@ jobs: - uses: actions-rs/cargo@v1 name: build docs with: - command: doc - args: --all --no-deps + command: +nightly doc + args: --all --no-deps --features nightly,typenum - uses: peaceiris/actions-gh-pages@v4 name: push docs From 02bbdf8528b7a977d31c30444c36a064762ece55 Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Sat, 4 May 2024 21:54:04 +0200 Subject: [PATCH 18/25] include typenum feature in ci doc-check --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d7c8083..4b42143b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -146,4 +146,4 @@ jobs: RUSTDOCFLAGS: '-D warnings' with: command: doc - args: --all --no-deps --document-private-items + args: --all --no-deps --document-private-items --features typenum From 8a9775ab1ebdb01a25d9d547756b094ce4310c72 Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Sat, 4 May 2024 22:07:18 +0200 Subject: [PATCH 19/25] nightly features only used with -F nightly --- core/src/hlist.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/hlist.rs b/core/src/hlist.rs index 6e2f6fe9..9f4c6528 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -60,7 +60,7 @@ use crate::traits::{Func, IntoReverse, Poly, ToMut, ToRef}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -#[doc(cfg(feature = "typenum"))] +#[cfg_attr(feature = "nightly", doc(cfg(feature = "typenum")))] #[cfg(feature = "typenum")] pub use typenum; #[cfg(feature = "typenum")] @@ -73,7 +73,7 @@ use std::ops::Add; /// An HList is a heterogeneous list, one that is statically typed at compile time. In simple terms, /// it is just an arbitrarily-nested Tuple2. pub trait HList: Sized { - #[doc(cfg(feature = "typenum"))] + #[cfg_attr(feature = "nightly", doc(cfg(feature = "typenum")))] /// The type-level encapsulation of the lists length, using `typenum` under the hood. /// /// # Examples @@ -1510,6 +1510,7 @@ where } } +#[cfg_attr(feature = "nightly", doc(cfg(feature = "std")))] #[cfg(feature = "std")] #[allow(clippy::from_over_into)] impl Into> for HNil { From f39266f2df815799b37366ad365d8c507ea8eb63 Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Sat, 4 May 2024 22:14:14 +0200 Subject: [PATCH 20/25] cargo fmt --all --- core/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/lib.rs b/core/src/lib.rs index 38b7c057..9290d2f1 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,9 +1,8 @@ -// This feature allows `cargo +nightly doc --F $GATED_FEATURES` to include +// This feature allows `cargo +nightly doc --F $GATED_FEATURES` to include // said features as well as show that they are behind a feature gate, like so: // #[doc(cfg(feature = "$GATED_FEATURE"))] // ...without adding nightly requirement to non-doc builds #![cfg_attr(feature = "nightly", feature(doc_cfg))] - #![doc(html_playground_url = "https://play.rust-lang.org/")] //! Frunk Core //! From ce74350067da1a77c468f05f3af8ae092050e26b Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Mon, 6 May 2024 12:51:27 +0200 Subject: [PATCH 21/25] Revert nightly stuff. Let error+suggestions help. --- .github/workflows/rustdoc.yml | 6 +++--- core/Cargo.toml | 1 - core/src/hlist.rs | 5 ----- core/src/lib.rs | 5 ----- 4 files changed, 3 insertions(+), 14 deletions(-) diff --git a/.github/workflows/rustdoc.yml b/.github/workflows/rustdoc.yml index 1b3fc367..83923d17 100644 --- a/.github/workflows/rustdoc.yml +++ b/.github/workflows/rustdoc.yml @@ -15,7 +15,7 @@ jobs: - uses: actions-rs/toolchain@v1 with: - toolchain: nightly + toolchain: stable override: true - uses: Swatinem/rust-cache@v2 @@ -23,8 +23,8 @@ jobs: - uses: actions-rs/cargo@v1 name: build docs with: - command: +nightly doc - args: --all --no-deps --features nightly,typenum + command: doc + args: --all --no-deps --features typenum - uses: peaceiris/actions-gh-pages@v4 name: push docs diff --git a/core/Cargo.toml b/core/Cargo.toml index 8b6b7a82..e88d8923 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -16,7 +16,6 @@ travis-ci = { repository = "lloydmeta/frunk" } default = ["std"] std = [] typenum = ["dep:typenum"] -nightly = [] [dependencies] serde = { version = "^1.0", optional = true, features = [ "derive" ] } diff --git a/core/src/hlist.rs b/core/src/hlist.rs index 9f4c6528..e0c694aa 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -60,7 +60,6 @@ use crate::traits::{Func, IntoReverse, Poly, ToMut, ToRef}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -#[cfg_attr(feature = "nightly", doc(cfg(feature = "typenum")))] #[cfg(feature = "typenum")] pub use typenum; #[cfg(feature = "typenum")] @@ -73,7 +72,6 @@ use std::ops::Add; /// An HList is a heterogeneous list, one that is statically typed at compile time. In simple terms, /// it is just an arbitrarily-nested Tuple2. pub trait HList: Sized { - #[cfg_attr(feature = "nightly", doc(cfg(feature = "typenum")))] /// The type-level encapsulation of the lists length, using `typenum` under the hood. /// /// # Examples @@ -1471,7 +1469,6 @@ where } } -#[cfg_attr(feature = "nightly", doc(cfg(feature = "std")))] #[cfg(feature = "typenum")] #[cfg(feature = "std")] #[allow(clippy::from_over_into)] @@ -1492,7 +1489,6 @@ where } } #[cfg(not(feature = "typenum"))] -#[cfg_attr(feature = "nightly", doc(cfg(feature = "std")))] #[cfg(feature = "std")] #[allow(clippy::from_over_into)] impl Into> for HCons @@ -1510,7 +1506,6 @@ where } } -#[cfg_attr(feature = "nightly", doc(cfg(feature = "std")))] #[cfg(feature = "std")] #[allow(clippy::from_over_into)] impl Into> for HNil { diff --git a/core/src/lib.rs b/core/src/lib.rs index 9290d2f1..02956918 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,8 +1,3 @@ -// This feature allows `cargo +nightly doc --F $GATED_FEATURES` to include -// said features as well as show that they are behind a feature gate, like so: -// #[doc(cfg(feature = "$GATED_FEATURE"))] -// ...without adding nightly requirement to non-doc builds -#![cfg_attr(feature = "nightly", feature(doc_cfg))] #![doc(html_playground_url = "https://play.rust-lang.org/")] //! Frunk Core //! From 906c499f6890f2cf86da9dceb74d1dcdc753f8ad Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Mon, 6 May 2024 13:08:05 +0200 Subject: [PATCH 22/25] Simplify typnum inclusion --- core/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/Cargo.toml b/core/Cargo.toml index e88d8923..bb8dbc97 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -19,7 +19,7 @@ typenum = ["dep:typenum"] [dependencies] serde = { version = "^1.0", optional = true, features = [ "derive" ] } -typenum = { version = "1.17.0", optional = true, default-features = false, features = ["no_std"] } +typenum = { version = "1.17.0", optional = true } [dev-dependencies.frunk_derives] path = "../derives" From 7cb70529df5b8444066ac752d8d61c025158ffa4 Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Mon, 6 May 2024 13:28:29 +0200 Subject: [PATCH 23/25] Restore the core no_std --- core/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/lib.rs b/core/src/lib.rs index 02956918..bc16035f 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,3 +1,4 @@ +#![cfg_attr(not(feature = "std"), no_std)] #![doc(html_playground_url = "https://play.rust-lang.org/")] //! Frunk Core //! From fb310a6667f72cbf8302f75a82a7804cd152ee87 Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Mon, 6 May 2024 13:28:43 +0200 Subject: [PATCH 24/25] refine doc-test --- core/src/hlist.rs | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/core/src/hlist.rs b/core/src/hlist.rs index e0c694aa..5284ae29 100644 --- a/core/src/hlist.rs +++ b/core/src/hlist.rs @@ -77,7 +77,7 @@ pub trait HList: Sized { /// # Examples /// ``` /// # fn main() { - /// use frunk_core::hlist::typenum::Unsigned; + /// use frunk_core::hlist::typenum::{self, Unsigned }; /// use frunk::prelude::*; /// use frunk_core::HList; /// @@ -85,15 +85,13 @@ pub trait HList: Sized { /// type LenTwo = HList![bool, ()]; /// /// // Attach a constraint that ensures constraints are met at type-check time - /// fn type_len_constraint>() {} + /// fn type_len_constraint>() {} /// /// /// /// // Won't compile: the length of LenThree doesn't meet the less-than-3 requirement - /// // let _ = type_len_constraint::<::Len>(); - /// - /// // ...this works, though - /// let _ = type_len_constraint::<::Len>(); + /// // let _fail = type_len_constraint::<::Len>(); + /// let _is_good = type_len_constraint::<::Len>(); /// /// // Pull out the length of the list in the word-size of your choosing. /// let byte: u8 = <::Len>::U8; @@ -103,6 +101,25 @@ pub trait HList: Sized { /// assert_eq!(::Len::U8, 3u8); /// # } /// ``` + /// + /// ```compile_fail + /// # fn main() { + /// use frunk_core::hlist::typenum::{self, Unsigned }; + /// use frunk::prelude::*; + /// use frunk_core::HList; + /// + /// type LenThree = HList![bool, (), u8]; + /// type LenTwo = HList![bool, ()]; + /// + /// // Attach a constraint that ensures constraints are met at type-check time + /// fn type_len_constraint>() {} + /// + /// + /// + /// // Won't compile: the length of LenThree doesn't meet the less-than-3 requirement + /// let _ = type_len_constraint::<::Len>(); + /// # } + /// ``` #[cfg(feature = "typenum")] type Len: Unsigned; From 424d7699dd655bac8394e1aac6651bf3a7c00c6d Mon Sep 17 00:00:00 2001 From: Ben PHL Date: Mon, 6 May 2024 14:31:30 +0200 Subject: [PATCH 25/25] Lift the typenum feature to root toml --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 4cf4331b..b1e3cdb6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ default = ["validated", "proc-macros"] validated = ["std"] proc-macros = ["frunk_proc_macros"] std = ["frunk_core/std"] +typenum = ["frunk_core/typenum"] [profile.bench] opt-level = 3