inherent-pub

Crates.ioinherent-pub
lib.rsinherent-pub
version0.2.1
sourcesrc
created_at2018-10-31 12:09:51.140549
updated_at2020-01-18 17:28:40.333253
descriptionMark methods in `impl Trait for Type` blocks inherent to the type
homepage
repositoryhttps://github.com/idanarye/rust-inherent-pub
max_upload_size
id93793
size39,828
Owners (github:oxidd:owners)

documentation

https://idanarye.github.io/rust-inherent-pub/

README

Build Status Latest Version Rust Documentation

Rust Inherent Pub

Motivation

If you impl a trait on a type, you'll only be able to use the methods in that impl block if you import the trait:

mod geometry {
    pub trait Length {
        fn length(&self) -> f64;
    }

    pub struct Vector(pub f64, pub f64);

    impl Length for Vector {
        fn length(&self) -> f64 {
            let Vector(x, y) = self;
            (x.powi(2) + y.powi(2)).sqrt()
        }
    }
}

fn main() {
    // Compilation error: we did not `use geometry::Length` so we can't access `length()`
    assert!(geometry::Vector(3.0, 4.0).length() == 5.0);
}

But what if the method is a natural member of the type itself, not just the trait? Shouldn't we be able to just access the length() of any Vector without having to explicitly tell Rust that we are using Length?

Enter the #[inherent_pub] procedural macro attribute!

Usage

With #[inherent_pub], we can make it so length() can be used without importing the Length trait - just annotated the impl block and mark the method as pub:

mod geometry {
    use inherent_pub::inherent_pub;

    pub trait Length {
        fn length(&self) -> f64;
    }

    pub struct Vector(pub f64, pub f64);

    #[inherent_pub]
    impl Length for Vector {
        pub fn length(&self) -> f64 {
            let Vector(x, y) = self;
            (x.powi(2) + y.powi(2)).sqrt()
        }
    }
}

fn main() {
    assert!(geometry::Vector(3.0, 4.0).length() == 5.0);
}

How the desugaring works?

#[inherent_pub] removes the pub from the methods and adds another impl block with inherent methods that get redirected to the trait ones. So:

impl Foo for Bar {
    #[inherent_pub]
    pub fn foo(self) {
        // Some code
    }
}

Gets desugared to:

impl Foo for Bar {
    fn foo(self) {
        // Some code
    }
}

impl Bar {
    #[doc(hidden)]
    #[inline(always)]
    pub fn foo(self) {
        <Self as Foo>::(self)
    }
}

Rather than handling special arguments like ignored arguments that start with (or are) a single underscore _ or pattern arguments, #[inherent_pub] simply replaces all arguments (other than self) with generic names. So:

impl Foo for Bar {
    #[inherent_pub]
    pub fn foo(self, a: i32, (b, c): (i32, i32), _: i32) {
        // Some code
    }
}

Gets desugared to:

impl Foo for Bar {
    fn foo(self, a: i32, (b, c): (i32, i32), _: i32) {
        // Some code
    }
}

impl Bar {
    #[doc(hidden)]
    #[inline(always)]
    pub fn foo(self, arg1: i32, arg2: i32, arg3: i32) {
        <Self as Foo>::(self, arg1, arg2, arg3)
    }
}
Commit count: 16

cargo fmt