Crate forward_traits

source ·
Expand description

This crate provides general mechanisms for implementing traits on types by forwarding an implementation provided by another type.

Two different forwarding methods are provided: Forwarding traits implemented by members, and forwarding traits implemented by types that the receiver type can convert to. These methods may be used in combination on the same receiver type. This crate fully supports generic traits and struct types.

For more details about capabilities and limitations, see the documentation pages for the individual macros.

§Basics

In order to forward a trait, some basic things are needed.

use forward_traits::{forwardable, forward_receiver, forward_traits};

We need a trait definition which is annotated with information which is used to generate forwarded implementations. This is done by applying the #[forwardable] attribute to the definition.

#[forwardable]
trait FooTrait
{
	type Bar;

	fn foo (&self) -> &Self::Bar;

	const BAZ: u32;
}

Then we need a type which initially implements this trait.

struct A {}

impl FooTrait for A
{
	type Bar = Self;

	fn foo (&self) -> &Self::Bar { self }

	const BAZ: u32 = 42;
}

Next, we need a type for which we want to implement this trait by forwarding the implementation found on the initially implementing type. There are a few different ways to define such a type, but here we will demonstrate the newtype idiom. This type needs to be annotated with the #[forward_receiver] attribute.

#[forward_receiver]
struct B (A);

Lastly, we need to specify that we want to forward a trait. In this case, we want to forward a trait implemented by a member, so we write:

forward_traits! (for B . 0 impl FooTrait);

And now we can see that the trait is properly forwarded.

assert_eq! (<B as FooTrait>::BAZ, 42);

§Re-Exporting Forwardable Traits

When re-exporting forwardable traits, the #[forwardable] attribute should be applied to the use statement as well. Note that the attribute will interpret every item in the use tree as a trait that should be forwardable. If you want to re-export items that aren’t forwardable traits from the same module(s), you’ll need to separate those re-exports out into another use statement;

use forward_traits::forwardable;

mod inner
{
	use forward_traits::forwardable;

	#[forwardable]
	pub trait Foo {}

	pub struct Bar {}
}

#[forwardable]
pub use inner::Foo;

pub use inner::Bar;

§Traits in Other Crates

Forwarding traits works with traits in other crates, so long as those trait definitions are annotated with #[forwardable].

If not, then annotations must be supplied separately. When supplying annotations in this way, the trait is imported (or re-exported if a visibility modifier is supplied) at the location of the annotation macro. When forwarding this trait, you must refer to this import/re-export (or a re-export thereof).

use forward_traits
::{
	supply_forwarding_info_for_trait,
	forward_receiver,
	forward_traits
};

// This has the side-effect of importing IntoIterator into the current scope.
supply_forwarding_info_for_trait!
(
	std::iter::IntoIterator,
	trait
	{
		type Item;
		type IntoIter;
		fn into_iter (self) -> Self::IntoIter;
	}
);

#[forward_receiver]
struct VecWrapper <T> (Vec <T>);

// Note that we are referring to the IntoIterator in the current scope.
forward_traits! (for VecWrapper . 0 impl IntoIterator);

// Now we can call the trait method on the wrapper type.
VecWrapper (vec! (1, 2, 3)) . into_iter ();

Macros§

  • The namesake of the crate, this macro generates trait implementations by delegating the trait items to another type.
  • This macro allows the user to supply forwarding information for a trait in an external crate that they do not control.

Attribute Macros§

  • This attribute annotates type definitions with forwarding information.
  • This attribute primarily annotates trait definitions with forwarding information. Secondarily, it is also used to make sure that the forwarding info is properly re-exported along with the traits that it belongs to.