intuple 0.2.0

Convert structs and enums into tuples (of refs) and back - recursive, ignore fields
Documentation

Features

🐍 convert a struct into a tuple and back ðŸĶŽ convert an enum into a tuple and back ðŸĶĒ get a tuple of (mut) references of fields of a struct 🐓 get a tuple of (mut) references of fields of an enum ðŸĶĨ ignore specific fields ðŸĶ† do it all recursively

Usage

🐠 add intuple to the dependencies in the Cargo.toml:

[dependencies]
intuple = "0.2"

ðŸĶ€ use/import everything into rust:

use intuple::*;

ðŸĶš multiple ways to convert:

#[derive(Intuple)]
struct Struct {a:u32, b:u32, c:u32}

fn main(){
    // use std traits
    let strct: Struct = (3,2,1).into();
    let tuple = <(u32, u32, u32)>::from(strct);
    let strct = Struct::from((3,2,1));
    let tuple: (u32, u32, u32) = strct.into();
    // OR intuple trait
    let strct = Struct::from_tuple((3,2,1));
    let tuple = strct.into_tuple(); // or strct.intuple()
    // references
    let strct = Struct::from_tuple((3,2,1));    
    let tupref = strct.as_tuple_ref(); // (&u32,&u32,&u32)
    let tupref = strct.as_tuple_ref_mut(); // (&mut u32,&mut u32,&mut u32)
    *tupref.1 = 3;
}

Tuple Type

ðŸĶŠ access the resulting tuple types through a qualified path:

#[derive(Intuple)]
struct Nice {a:u32, b:u32, c:u32}
fn main(){
    let tup: <Nice as Intuple>::Tuple = (3,2,1);
    let tup: (u32, u32, u32) = (3,2,1); // <- same as above
    // reference tuple types
    let tup: <Nice as IntupleRef>::Tuple = (&3,&2,&1);
    let tup: (&u32, &u32, &u32) = (&3,&2,&1); // <- same as above
    // mut reference tuple types
    let tup: <Nice as IntupleRef>::TupleMut = (&mut 3,&mut 2,&mut 1);
    let tup: (&mut u32, &mut u32, &mut u32) = (&mut 3,&mut 2,&mut 1); // <- same as above
}

Ignoring

ðŸĶĨ ignore specific fields with #[igno]/#[ignore] ðŸŧ or #[intuple(igno)]/#[intuple(ignore)] 🐞 ignored fields need to implement Default while converting to a struct

#[derive(Intuple)]
struct Struct {a:u32, #[igno] b:u32, c:u32}
fn main(){
    let strct = Struct::from((2,1));     
    // => {a:2, b:0, c:1}  
    let tuple: (u32, u32) = strct.into();
    // => (2, 1)
}

Recursion

ðŸĶŠ convert recursively with #[recursive]/#[rcsv] ðŸĶ or #[intuple(rcsv)]/#[intuple(recursive)] 🐞 recursive fields need to derive Intuple

#[derive(Intuple)]
struct Struct {a:u32, b:u32, c:u32}
#[derive(Intuple)]
struct Recursive {a:u32, #[recursive] b:Struct, c:u32}
fn main(){
    let rcsv: Recursive = (9,(3,2,1),8).into(); 
    // => Recursive{a:9, b:Struct{a:3,b:2,c:1}, c:8}
    let tuple: RecursiveIntuple = rcsv.into(); 
    // => (9,(3,2,1),8)
}

ðŸĶ† recursion also works with .as_tuple_ref() and as_tuple_ref_mut()

#[derive(Intuple)]
struct Struct {a:u32, b:u32, c:u32}
#[derive(Intuple)]
struct Recursive {a:u32, #[recursive] b:Struct, c:u32}
fn main(){
    let rcsv = Recursive::from((9,(3,2,1),8)); 
    let tuple = rcsv.as_tuple_ref(); 
    // => (&9,(&3,&2,&1),&8)
}

Enums

🙉 converting enums to tuples isn't as straight forward as structs, therefore two methods are implemented!

🐍 1. Positional

🐆 using Intuple - no additional enums or structs are generated ðŸĒ field tuples are wrapped in an Option<>, which are inside another tuple ðŸĶŽ the outer tuple has as many fields as there are enum variants 🐊 the required None variant will convert to (None,None,None,...) 🐉 any other variant will occupy a slot, depending on its position (None,Some(tuple),None,...)

// Positional
#[derive( Intuple, Debug )]
// enums require a 'None' variant
enum Enum { None, Unit, Unnamed(u32,u32), Another(u8,u8) }
fn main(){
    let enum = Enum::Unnamed(1,2); 
    let tuple = enum.as_tuple_ref(); 
    // => (None, Some((&1,&2)), None)
    let tuple = enum.into_tuple(); 
    // => (None, Some((1,2)), None)
    let enum = Enum::None; 
    let tuple = rcsv.into_tuple(); 
    // => (None,None,None)
}

ðŸĶŠ 2. Generated Tuple Enums

🐈 using IntupleEnum - three additional enums will be generated: 🐕 {EnumName}Intuple, {EnumName}IntupleRef and {EnumName}IntupleRefMut ðŸĶ„ each of those will use the original variant names and contain a tuple 🐔 to set derives for them, use #[intuple(derive(...))] ⚠ to use them recursivly ANYWHERE, use #[recursive_enum] or #[rcsve] ðŸĶĒ .into()/.from(..) are implemented, but the custom methods change to: 🐓 .from_tuple_enum(..), .into_tuple_enum(), .as_tuple_enum_ref() and .as_tuple_enum_ref_mut()

// Generated
#[derive( IntupleEnum, Debug )]
#[intuple(derive( Debug ))]
enum Enum { Unit, Unnamed(u32,u32), Another(u8,u8) }
fn main(){
    let enum = Enum::Unnamed(1,2); 
    let tuple = enum.as_tuple_enum_ref(); 
    // => EnumIntupleRef::Unnamed((&1,&2))
    let tuple = enum.into_tuple_enum(); 
    // => EnumIntupleRef::Unnamed((1,2))
}

Example: Serde - Thinking out of the box

ðŸĶ„ You could use serde without implementing Serialize/Deserialize 🐔 This only works with the positional enum tuples!

use intuple::*;

#[derive(Intuple)]
struct Named{a:u32, b:u32, c:u32, d:u32, e:u32, f:u32}

fn main(){
    let named = Named::from((1,2,3,4,5,6));
    let json = serde_json::to_string(&named.as_tuple_ref()).unwrap();
    println!("{}",json); //=> "[1,2,3,4,5,6]"

    let tuple = serde_json::from_str::<<Named as Intuple>::Tuple>(&json).unwrap();
    let named_again = Named::from(tuple);
    // named == named_again
}

More Information

ðŸĶŽ Changelog ðŸą GitHub ðŸ‘ū Discord Server


License