The [cain!] macro is a macro that rewrites sequential Rust branch statements into nested branches

Related tags

Web programming cain
Overview

Note! This crate is experimental and under development. It may include bugs that alter the behavior of your code in unexpected ways. You should review the expanded code from the macro before use, and report any bugs you may find to the bug tracker at https://github.com/frxstrem/cain/issues.

The [cain!] macro is a macro that rewrites sequential Rust branch statements into nested branches.

This can be useful in cases where you want to have branches with different types that behave similarly, for example concrete types with a common trait, without having to use runtime trait objects like Box .

The disadvantage of this is that the amount of code grows exponentially relative to the number of sequential branches in the expanded code.

MSRV

The minimal supported Rust version for cain is 1.57.0 (December 2021).

Example

The code:

fn foo(): Result
   
     { .. }

let a = cain! {
  let value = match foo() {
    Ok(n) => n,
    Err(b) => b,
  };

  value.to_string()
};

   

Will be expanded by the cain! macro into the code:

fn foo(): Result
   
     { .. }

let a = {
  match foo() {
    Ok(n) => {
      let value = n;
      n.to_string()
    },
    Err(b) => {
      let value = b;
      b.to_string()
    }
  }
};

   
You might also like...
A Rust web framework

cargonauts - a Rust web framework Documentation cargonauts is a Rust web framework intended for building maintainable, well-factored web apps. This pr

A Rust library to extract useful data from HTML documents, suitable for web scraping.

select.rs A library to extract useful data from HTML documents, suitable for web scraping. NOTE: The following example only works in the upcoming rele

openapi schema serialization for rust

open api Rust crate for serializing and deserializing open api documents Documentation install add the following to your Cargo.toml file [dependencies

📮 An elegant Telegram bots framework for Rust
📮 An elegant Telegram bots framework for Rust

teloxide A full-featured framework that empowers you to easily build Telegram bots using the async/.await syntax in Rust. It handles all the difficult

Sōzu HTTP reverse proxy, configurable at runtime, fast and safe, built in Rust. It is awesome! Ping us on gitter to know more

Sōzu · Sōzu is a lightweight, fast, always-up reverse proxy server. Why use Sōzu? Hot configurable: Sozu can receive configuration changes at runtime

A Rust application which funnels external webhook event data to an Urbit chat.
A Rust application which funnels external webhook event data to an Urbit chat.

Urbit Webhook Funnel This is a simple Rust application which funnels external webhook event data to an Urbit chat. This application is intended to be

A html document syntax and operation library written in Rust, use APIs similar to jQuery.

Visdom A server-side html document syntax and operation library written in Rust, it uses apis similar to jQuery, left off the parts thoes only worked

Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.

Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.

Starlight is a JS engine in Rust which focuses on performance rather than ensuring 100% safety of JS runtime.

starlight Starlight is a JS engine in Rust which focuses on performance rather than ensuring 100% safety of JS runtime. Features Bytecode interpreter

Comments
  • Improper identifier hygiene in match arm patterns

    Improper identifier hygiene in match arm patterns

    Reported by Reddit user u/pinespear in this comment:

    You have some problems with hygiene of identifiers. Basically, identifiers from inner scope can pollute outer scope and it leads to functionally different logic being executed.

    Example is a bit artificial, because I tried to minimize it to show the idea:

    This works without panic:

    let val = Some(vec![0_usize]);
    
    let mut v = vec![1];
    
    match val {
        Some(mut v) => drop(v.pop()),
        None => {}
    };
    
    v.pop().unwrap();
    

    This panics:

    let val = Some(vec![0_usize]);
    
    let mut v = vec![1];
    
    cain! {
        let _ = match val {
            Some(mut v) => drop(v.pop()),
            None => {}
        };
    
        v.pop().unwrap();
    }
    

    Reason it panics is it expands to:

    let val = Some(<[_]>::into_vec(box [0_usize]));
    let mut v = <[_]>::into_vec(box [1]);
    {
        match val {
            Some(mut v) => {
                let _ = drop(v.pop());
                v.pop().unwrap();
            }
            None => {
                let _ = {};
                v.pop().unwrap();
            }
        }
    }
    

    and second v.pop() gets executed on inner identifier v except of outer identifier v

    This is trivial case which can be solved by "sanitizing" identifiers in arms and "un-sanitizing" them in the scope so they won't get leaked:

        match val {
            Some(mut v_randomized213345) => {
                let _ = {
                    let mut v = v_randomized213345;
                    drop(v.pop())
                };
                v.pop().unwrap();
            }
            None => {
                let _ = {};
                v.pop().unwrap();
            }
        }
    

    but there may be other cases which are harder to notice, I'm not sure how can you formally guarantee that code logic and behavior won't get affected.

    bug 
    opened by frxstrem 0
Owner
Fredrik Østrem
Fredrik Østrem
Rust Macro which loads files into the rust binary at compile time during release and loads the file from the fs during dev.

Rust Embed Rust Custom Derive Macro which loads files into the rust binary at compile time during release and loads the file from the fs during dev. Y

Peter 1k Jan 5, 2023
Rust I18n is use Rust codegen for load YAML file storage translations on compile time, and give you a t! macro for simply get translation texts.

Rust I18n Rust I18n is use Rust codegen for load YAML file storage translations on compile time, and give you a t! macro for simply get translation te

Longbridge 73 Dec 27, 2022
lispr is a Rust macro that tries to implement a small subset of LISPs syntax in Rust

lispr lispr is a Rust macro that tries to implement a small subset of LISPs syntax in Rust. It is neither especially beautiful or efficient since it i

Jan Vaorin 0 Feb 4, 2022
Attribute macro that generates negated versions of`is_something` functions

negate negate is a simple attribute macro that negates a given function. Usage #[negate] Given a function of the form is_* that returns a boolean valu

Vinícius Miguel 9 Mar 4, 2022
Tools that parsing Rust code into UML diagram (in dot format currently).

rudg Rust UML Diagram Generator Tools that parsing Rust code into UML diagram (in dot format currently). Usage $ rudg.exe --help rudg 0.1.0 USAGE:

Zhai Yao 16 Nov 13, 2022
Turn GitHub into an RSS reader

NotCraft::NotFeed An RSS reader running entirely from your GitHub repo. Free hosting on GitHub Pages. No ads. No third party tracking. No need for bac

NotCraft 22 Nov 30, 2022
ditch poetry for pip. converts pyproject.toml into requirements.txt.

Say No To Poetry Did you grow up using just pip or conda? Are you being forced to use poetry everywhere at work? They try to convince you poetry just

Jaivarsan 7 Nov 6, 2022
Merge multiple Juniper object definitions into a single object type.

juniper-compose Merge multiple Juniper object definitions into a single object type. crates.io | docs | github Motivation You are building a GraphQL s

Kit Isaev 3 Aug 5, 2022
Turn any web page into a desktop app (but, lightweight <1MB)

Intro Turn any web page into a desktop app (but, lightweight <1MB) The bundle will be less than 2MB Demo: https://i.imgur.com/BLr03oF.mp4 Install carg

null 9 Dec 27, 2022
Rust/Axum server implementation with PCR(Prisma Client Rust)

Realworld Rust Axum Prisma This project utilizes Rust with the Axum v0.7 framework along with the Prisma Client Rust to build a realworld application.

Neo 3 Dec 9, 2023