Frunk 0.2.0 released ! ๐ŸŽ‰

:tada:frunk 0.2.0 :tada:

Thanks to amazing contributions from 2 awesome new main contributors, @Centril and @ExpHP, v0.2.0 of frunk contains heaps of improvements in terms of utility, ergonomics, and documentation.

What is frunk?

At itโ€™s core, frunk brings Generic and LabelledGeneric to Rust. Why? Because these abstractions can help you Scrap Your Boilerplate, for example, by allowing totally boilerplate-free transformations between different structs.

Examples

Type-safe, boilerplate-free, zero-cost transformations between different structs:

#[derive(LabelledGeneric)]
struct SavedUser<'a> {
    id: u32,
    first_name: &'a str,
    last_name: &'a str,
    age: usize,
}

// id is gone, and fields are swapped :(
#[derive(LabelledGeneric)]
struct DeletedUser<'a> {
    last_name: &'a str,
    age: usize,
    first_name: &'a str,
}

let s_user = SavedUser {
        id: 1,
        first_name: "Joe",
        last_name: "Blow",
        age: 30,
    };

// transform !
let d_user: DeletedUser = frunk::transform_from(s_user);

Coproduct types

// I32Bool is a type that can only contain one of i32 or bool.
type I32Bool = Coprod!(i32, bool);

fn work_it(v: I32Bool) -> String {
  v.fold(
     poly_fn!(
         |_b: bool| -> String { format!("bool {}", i) },
         |i:  i32 | -> String { format!("i32  {}", i) },
     )
  )
}

assert_eq!(
  work_it(I32Bool::inject(3)), 
  "i32  3".to_string()
);

This is a small sample of what frunk offers. For more info, check out the repo and the docs.

Links

  1. frunkโ€™s Github repo
  2. Docs

Credit

Credit where itโ€™s due, frunk was heavily inspired by existing Haskell and Scala utilities and libraries.

  1. shapeless
  2. generic-deriving
7 Likes

Have you guys become experts in playing mental type tetris with compiler error messages when things go sideways during development? :slight_smile:

4 Likes

It is almost like playing chess with the compiler :stuck_out_tongue: One step forwardโ€ฆ

4 Likes
error[E0275]: overflow evaluating the requirement `_: std::marker::Sized`
  --> a.rs:1:8
   |
 1 |     One step forward...
   |              ^^^^^^^
   |
   = note: consider adding a `#![recursion_limit="10"]` attribute to your crate
   = note: required because of the requirements on the impl of `Step` for `&'_ Human`
   = note: required because of the requirements on the impl of `Step` for `&'_ (&'_ Human)`
   = note: required because of the requirements on the impl of `Step` for `&'_ (&'_ (&'_ Human))`
   = note: required because of the requirements on the impl of `Step` for `&'_ (&'_ (&'_ (&'_ Human)))`
   = note: required because of the requirements on the impl of `Step` for `&'_ (&'_ (&'_ (&'_ (&'_ Human))))`
6 Likes