Giter Club home page Giter Club logo

ghost.org's Introduction

Define your own PhantomData

github crates.io docs.rs build status

This crate makes it possible to define your own PhantomData and similarly behaved unit types with generic parameters, which is not permitted in ordinary Rust.

[dependencies]
ghost = "0.1"

Supports rustc 1.31+

Background

PhantomData as defined by the Rust standard library is magical in that the same type is impossible to define in ordinary Rust code. It is defined in the standard library like this:

#[lang = "phantom_data"]
pub struct PhantomData<T: ?Sized>;

The #[lang = "..."] attribute indicates that this is a lang item, a special case known to the compiler. It is the only type permitted to carry an unused type parameter.

If we try to define an equivalent unit struct with type parameter, the compiler rejects that.

struct MyPhantom<T: ?Sized>;
error[E0392]: parameter `T` is never used
 --> src/main.rs:1:18
  |
1 | struct MyPhantom<T: ?Sized>;
  |                  ^ unused type parameter
  |
  = help: consider removing `T` or using a marker such as `std::marker::PhantomData`

This crate provides a #[phantom] attribute that makes it possible to define unit structs with generic parameters.

Examples

use ghost::phantom;

#[phantom]
struct MyPhantom<T: ?Sized>;

fn main() {
    // Proof that MyPhantom behaves like PhantomData.
    let _: MyPhantom<u8> = MyPhantom::<u8>;
    assert_eq!(0, std::mem::size_of::<MyPhantom<u8>>());
}

// Proof that MyPhantom is not just a re-export of PhantomData.
// If it were a re-export, these would be conflicting impls.
trait Trait {}
impl<T> Trait for std::marker::PhantomData<T> {}
impl<T> Trait for MyPhantom<T> {}

// Proof that MyPhantom is local to the current crate.
impl<T> MyPhantom<T> {
}

The implementation accepts where-clauses, lifetimes, multiple generic parameters, and derives. Here is a contrived invocation that demonstrates everything at once:

use ghost::phantom;

#[phantom]
#[derive(Copy, Clone, Default, Hash, PartialOrd, Ord, PartialEq, Eq, Debug)]
struct Crazy<'a, V: 'a, T> where &'a V: IntoIterator<Item = T>;

fn main() {
    let _ = Crazy::<'static, Vec<String>, &'static String>;

    // Lifetime elision.
    let crazy = Crazy::<Vec<String>, &String>;
    println!("{:?}", crazy);
}

Variance

The #[phantom] attribute accepts attributes on individual generic parameters (both lifetime and type parameters) to make them contravariant or invariant. The default is covariance.

  • #[contra] โ€” contravariant generic parameter
  • #[invariant] โ€” invariant generic parameter

The implications of variance are explained in more detail by the Subtyping chapter of the Rustonomicon.

use ghost::phantom;

#[phantom]
struct ContravariantLifetime<#[contra] 'a>;

fn f<'a>(arg: ContravariantLifetime<'a>) -> ContravariantLifetime<'static> {
    // This coercion is only legal because the lifetime parameter is
    // contravariant. If it were covariant (the default) or invariant,
    // this would not compile.
    arg
}

#[phantom]
struct Demo<A, #[contra] B, #[invariant] C>;

Documentation

There are two alternatives for how to handle Rustdoc documentation on publicly exposed phantom types.

You may provide documentation directly on the phantom struct in the obvious way, but Rustdoc will blithely display the somewhat distracting implementation details of the mechanism emitted by the #[phantom] macro. This way should be preferred if you need to document any public methods, as methods will not be visible in the other alternative.

use ghost::phantom;

/// Documentation.
#[phantom]
pub struct MyPhantom<T: ?Sized>;

impl<T: ?Sized> MyPhantom<T> {
    /// Documentation on methods.
    pub fn foo() {}
}

If you aren't adding methods or don't need methods to be rendered in the documentation, the recommended idiom is as follows. Rustdoc will show a much less distracting type signature and all of your trait impls, but will not show inherent methods.

mod private {
    use ghost::phantom;

    #[phantom]
    pub struct MyPhantom<T: ?Sized>;
}

/// Documentation goes here.
#[allow(type_alias_bounds)]
pub type MyPhantom<T: ?Sized> = private::MyPhantom<T>;

#[doc(hidden)]
pub use self::private::*;

Use cases

Entirely up to your imagination. Just to name one, how about a typed registry library that admits the following syntax for iterating over values registered of a particular type:

for flag in Registry::<Flag> {
    /* ... */
}

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

ghost.org's People

Contributors

dtolnay avatar eijebong avatar

Watchers

Dan.hn avatar

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.