Prismatic

An experimental Rust crate for decomposing the initialization of structs.

prism

Overview

A common idiom in Rust is to define a new function that initializes a struct. Sometimes this function can get quite large. If you try to decompose it into steps, you're often left with complicated signatures on private functions:

```rust impl Webpage { pub fn new(title: &str) -> Self { let window = Self::fetchwindow(); let document = Self::fetchdocument(); let body = Self::fetchbody(&document); let canvas = Self::createcanvas(&document); let context = Self::fetch_context(&canvas);

    Self::set_page_title(&document, title);
    Self::reset_styles(&document, &body);
    Self::add_canvas_to_page(&body, &canvas);
    Self::resize_canvas(&body, &canvas);
    Self::bind_resize_event(&window, &body, &canvas);

    Webpage { window, document, body, canvas, context }
}

fn fetch_body(document: &Document) -> Body {
  document.body().expect("failed to fetch body")
}

fn bind_resize_event(window: &Window, body: &Body, canvas: &canvas) {
  // ...
}

// ...

} ```

Prismatic

Prismatic provides a macro to make this a bit easier. It generates a special Init struct that can be used for initialization, reducing the overhead of extracting functions for each of the steps:

```rust

[macro_use]

extern crate prismatic;

[derive(New)]

[Sig = "title: &str"]

struct Webpage { window: Window, document: Document, body: Body, canvas: Canvas, context: Context, }

impl Init { fn init(&mut self, title: &str) { self.fetchwindow(); self.fetchdocument(); self.fetchbody(); self.createcanvas(); self.fetch_context();

    self.set_page_title(title);
    self.reset_styles();
    self.add_canvas_to_page();
    self.resize_canvas();
    self.bind_resize_event();
}

fn fetch_body(&mut self) {
    let body = self.document().body().expect("failed to fetch body");
    self.set_body(body);
}

fn bind_resize_event(&self) {
  // ...
}

// ...

} ```

In the example above, the fetch_body function uses the the document() getter method and sets the body with the set_body() setter method. Getters and setters are automatically generated for all fields in your struct during initialization.

Usage

Here's a minimal example:

```rust

[macro_use]

extern crate prismatic;

[derive(New)]

struct Foo { bar: usize }

impl Init { fn init(&mut self) { self.set_bar(123); } }

let foo = Foo::new() assert_eq!(foo.bar, 123); ```

The Sig attribute (short for Signature) can be used if the initializer requires additional arguments:

```rust

[derive(New)]

[Sig = "x: usize"]

struct Foo { bar: usize }

impl Init { fn init(&mut self, x: usize) { self.set_bar(x); } }

let foo = Foo::new(123); assert_eq!(foo.bar, 123); ```