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