Git Product home page Git Product logo

must-implement-trait's Introduction

must-implement-trait

CI Badge Crates.io

An attribute proc-macro which enforces that a type (auto-)implements the specified trait(s).

Usage

Apply the must_implement_trait attribute to your struct or enum:

use must_implement_trait::must_implement_trait;

#[must_implement_trait(Send)]
struct Resources {
    data: Rc<String>,
}

#[must_implement_trait(Send, UnwindSafe)]
enum ConfigSource {
    File(String),
    Database(DatabaseAdapter)
}

The attribute can take one or many trait names as parameters; it will enforce that all are implemented.

Motivation

Some traits, chiefly Send and Sync, are auto traits. This means that they are automatically implemented by the compiler, and rarely implemented (or un-implemented) by hand. Their implementations are implicit, and non-obvious to the reader without looking at documentation.

As a library author, you may want to guarantee to consumers that your exposed interface will carry these traits. It may also be helpful within one's own code to provoke an error near the source of the un-implementation rather than near a consumer which fails to compile due to a trait bound violation.

Consider the following example (examples/async-future-send.rs):

struct Resources {
    data: Rc<String>,
}

struct MyResourceManager {}

#[async_trait]
impl ResourceManager for MyResourceManager {
    async fn update_resources(resources: &Resources) {
        // Some code to update resources...
    }
    
}

We get an error within the update_resources function telling us:

error: future cannot be sent between threads safely
  --> examples/async-future-send.rs:21:54
   |
21 |       async fn update_resources(resources: &Resources) {
   |  ______________________________________________________^
22 | |         // Some code to update resources...
23 | |     }
   | |_____^ future returned by `__update_resources` is not `Send`
   |
   = help: within `Resources`, the trait `std::marker::Sync` is not implemented for `std::rc::Rc<std::string::String>`

By default, async-trait requires returned Futures to be Send. That is a rather natural choice, since async is often used in multi-threaded contexts. In this case, since we used an Rc rather than an Arc, Resources is not Send; we are given an error at the usage site. If Resources were in its own crate which is intended to be used in async contexts, the author may not realize they have made a breaking change by introducing an Rc.

In my experience, if working in a codebase which is async-oriented, it makes sense to ensure that most or all types are Send + Sync; it is easy to break downstream code if an auto-implementation changes implicitly.

By applying must_implement_trait, the error is moved to the type declaration:

error[E0277]: `std::rc::Rc<std::string::String>` cannot be sent between threads safely
  --> examples/async-future-send.rs:11:1
   |
11 | #[must_implement_trait(Send)]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::rc::Rc<std::string::String>` cannot be sent between threads safely
   |
   = help: within `Resources`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::string::String>`
   = note: required because it appears within the type `Resources`
   = help: see issue #48214
   = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

must-implement-trait's People

Contributors

wasabifan avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar

must-implement-trait's Issues

Publish proper docs

At the moment, the only documentation is the README, example and tests. It might be nice to write some proper docs on the attribute. That being said, there isn't much to document in the first place.

Fully document use-case for custom traits

In addition to the std-provided auto traits like Send and Sync, this crate is intended to be used for validating the applicability of traits which are applied as a generic impl block over some other family of types. In other words, using it to confirm that your own traits (or a library's traits) are auto-applied to a type you define. This should be documented with an example.

Support for types with generics

At the moment, the attribute disallows use on types with generic parameters. I haven't yet worked through whether a) there is a sensible behavior desired here, or b) whether there is a convenient mechanism for enforcing this without something significantly more complicated than the current unit-struct gadget.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.