Partially Constructable Tuples? #146
-
I think the same machinery you use for
The second feels like the more natural analog for tuples to me, but it seems to me you would want a mechanism like I'm still learning the details of CGP, so some of these particulars might not be right, but I think the general idea should be clear. My questions are:
My use case is implementing a compile-time isomorphism between tuples |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 2 replies
-
I spent a few hours trying to do some version of this myself. Accessors for any particular index are easy enough--in fact I got a lot closer with the unique types idea, but ultimately the compiler would complain about ambiguity: I couldn't find a way to let the compiler know the types were unique. It might be that the best you can do is give the fields names unrelated to their index and then treat them like a struct. That would at least give you the builder mechanisms. |
Beta Was this translation helpful? Give feedback.
-
Hi @rljacobson, thanks for your exploration! Aside from partial records and extensible builders, CGP has another undocumented feature for #[derive(Clone, Debug, Eq, PartialEq, HasFields)]
pub struct Person {
pub name: String,
pub age: u8,
}
let name = "Alice".to_owned();
let person1 = Person { name: name.clone(), age: 32 };
// Product![ Field<symbol!("name"), String>, Field<symbol!("age"), u8> ]
let product = person1.clone().to_fields();
assert_eq!(product, product![name.clone().into(), 32.into()]);
// Product![ Field<symbol!("name"), &String>, Field<symbol!("age"), &u8> ]
let product_ref = person1.to_fields_ref();
assert_eq!(product_ref, product![(&name).into(), (&32).into()]);
let person2 = Person::from_fields(product);
assert_eq!(person1, person2); The main difference between this and your approach is that the If you still want to use regular N-tuples with |
Beta Was this translation helpful? Give feedback.
-
If anyone is curious how you might implement the tuple → struct → tuple strategy for distinct named types (my use case), here's one way. This lets you convert a tuple to another tuple with the same types but different order. The trait solver computes the reordering via the builder mechanism of CGP. use cgp::core::field::CanBuildFrom; // Not in the prelude.
use cgp::prelude::*;
use paste::paste;
macro_rules! new_tuple {
($name:ident, ($($param:ident),+ )) => {
paste::paste!{
#[derive(Debug, Copy, Clone, HasFields, BuildField)]
struct $name {
$(pub [<_ $param:lower>] : $param,)+
}
impl From<($($param),+)> for $name {
fn from(value: ($($param),+)) -> Self {
let ( $( [<_ $param:lower>],)+ ) = value;
Self{
$( [<_ $param:lower>],)+
}
}
}
impl From<$name> for ($($param),+) {
fn from(value: $name) -> Self {
($( value.[<_ $param:lower>],)+)
}
}
}
};
}
new_tuple!(Tuple_1_2, (Type1, Type2) );
new_tuple!(Tuple_2_1, (Type2, Type1) );
#[test]
fn test_new_tuple() {
let unordered = (Type2, Type1);
let unordered_tuple = Tuple_2_1::from(unordered);
let ordered_tuple = Tuple_1_2::builder().build_from(unordered_tuple).finalize_build();
let ordered = ordered_tuple.into(); // Type inferred via assert.
assert_eq!((Type1, Type2), ordered);
} You could modify this in various ways, of course, but this is the basic idea. You can do this for any set of distinct types if you use the |
Beta Was this translation helpful? Give feedback.
Hi @rljacobson, thanks for your exploration! Aside from partial records and extensible builders, CGP has another undocumented feature for
HasFields
, which is that you can useFromFields
andToFields
to convert to/from theFields
type. Here is an example use: