#inherent #pub #impl-block #methods #traits #self #import

macro inherent-pub

Mark methods in impl Trait for Type blocks inherent to the type

3 unstable releases

0.2.1 Jan 18, 2020
0.2.0 Oct 31, 2018
0.1.0 Oct 31, 2018

#629 in Procedural macros

MIT license

10KB
104 lines

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)
    }
}

Dependencies

~1.5MB
~35K SLoC