Git Product home page Git Product logo

sealed-rs's Issues

Support #[sealed] on enum

Currently, using #[sealed] on an enum fails with expected struct or trait. I don't see a reason this shouldn't work on enums too, besides not being implemented in the macro.

Add sealing for specific functions

I recently read a very nice blog about sealed traits.
It talked about a few ways to seal not simply a trait, but specific methods that are part of the trait.
It is possible to seal a method, either for implementation, or also for use.

I am not sure if this would be a good addition to this crate, as it is quite niche, as well as somewhat different from what this crate is doing.

I think however, that it would make sense for the ecosystem that if this feature would be a thing, it would be in this crate, as it seems to me as a natural extension.

If others agree that it should be in here I'd be more than happy to make a PR for it, otherwise I'll make my own crate for it.

Allow to control visibility

While using pub(crate) mod allows to overcome nesting for impls, it also makes using #[sealed] pointless in bounds of a single crate: imagine usage in application crate, where the trait is declared in some module, not other crate.

It would be nice to control the visibility via attribute argument:

#[sealed]
pub trait T {}
// expands to
mod __seal_t {}

#[sealed(pub(crate))]
pub trait T {}
// expands to
pub(crate) mod __seal_t {}

// And even follow an arbitrary visiblity:
// https://doc.rust-lang.org/reference/visibility-and-privacy.html

#[sealed(pub(in crate::very::long::path))]
pub trait T {}
// expands to
pub(in crate::very::long::path) mod __seal_t {}

So, for the nesting case (which is quite rare, AFAIK), an user should specify the visibility explicitly, while for the usage in non-library crate, the sealing will work well out-of-the-box.

Allow to seal blanket impls

Synopsis

With the current implementation it's impossible to seal a trait having blanket implementations and foreign types. For example:

#[sealed]
pub trait AsSpan {
    fn as_span(&self) -> Span;
}

impl AsSpan for Span {  // foreign type, cannot place #[sealed]
    fn as_span(&self) -> Self { *self }
}

impl<T: Spanned> AsSpan for &T { // blanket impl, cannot place #[sealed]
    fn as_span(&self) -> Span { self.span() }
}

Proposed solution

Place #[sealed] attribute on impl blocks rather than on types:

#[sealed]
pub trait AsSpan {
    fn as_span(&self) -> Span;
}
// expands to:
// pub trait AsSpan: private::Sealed {
//     fn as_span(&self) -> Span;
// }
// mod private {
//     pub trait Sealed {}
// }

#[sealed]
impl AsSpan for Span {
    fn as_span(&self) -> Self { *self }
}
// expands to:
// impl AsSpan for Span {  // foreign type, cannot place #[sealed]
//     fn as_span(&self) -> Self { *self }
// }
// impl private::Sealed for Span {}

#[sealed]
impl<T: Spanned> AsSpan for &T {
    fn as_span(&self) -> Span { self.span() }
}
// expands to:
// impl<T: Spanned> AsSpan for &T {
//     fn as_span(&self) -> Span { self.span() }
// }
// impl<T: Spanned> private::Sealed for &T {}

Playground

More benefits

Also, having a flat trait signature like pub trait Sealed {} imposes problems with coherence for more complicated traits. Consider the following example:

pub trait Set<V> {}

impl<T> Set<Option<T>> for T {}
impl<T> Set<Option<T>> for Option<T> {}

This compiles perfectly well. But once we seal it, we loose the coherence:

pub trait Set<V>: private::Sealed {}
mod private {
    pub trait Sealed {}
}

impl<T> Set<Option<T>> for T {}
impl<T> private::Sealed for T {}

impl<T> Set<Option<T>> for Option<T> {}
impl<T> private::Sealed for Option<T> {}

Playground

To overcome this limitation, the private::Sealed trait should fully follow the parametrization of the original trait:

pub trait Set<V>: private::Sealed<V> {}
mod private {
    pub trait Sealed<V> {}
}

impl<T> Set<Option<T>> for T {}
impl<T> private::Sealed<Option<T>> for T {}

impl<T> Set<Option<T>> for Option<T> {}
impl<T> private::Sealed<Option<T>> for Option<T> {}

Playground

And we cannot do that by putting a #[sealed] attribute on top of a type rather than an impl block, because we simply don't have parametrization info there.

Traits with lifetimes fail to compile

#[sealed::sealed]
pub trait Testing<'a> {}

error[E0106]: missing lifetime specifier
  |
1 | #[sealed::sealed]
  | ^ expected named lifetime parameter
  |
  = note: this error originates in the attribute macro `sealed::sealed` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider using the `'a` lifetime
  |
1 | #<'a>[sealed::sealed]
  | ~~~~~

For more information about this error, try `rustc --explain E0106`.

Provide a simpler test for const-generics

As it stands, the test for const-generics fails for version 1.51.0

┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
error[E0277]: `[T; N]` is not an iterator
  --> tests/pass/13-const-generics.rs:11:33
   |
11 |         IntoIterator::into_iter(arr).collect()
   |                                 ^^^
   |                                 |
   |                                 expected an implementor of trait `IntoIterator`
   |                                 help: consider borrowing here: `&arr`
   |
   = note: the trait bound `[T; N]: IntoIterator` is not satisfied
   = note: required because of the requirements on the impl of `IntoIterator` for `[T; N]`
   = note: required by `into_iter`

error[E0599]: the method `collect` exists for array `[T; N]`, but its trait bounds were not satisfied
  --> tests/pass/13-const-generics.rs:11:38
   |
11 |         IntoIterator::into_iter(arr).collect()
   |                                      ^^^^^^^ method cannot be called on `[T; N]` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `[T; N]: Iterator`
           which is required by `&mut [T; N]: Iterator`
           `[T]: Iterator`
           which is required by `&mut [T]: Iterator`
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

Finding a simpler test that works would allow test runs for 1.50.0

Cannot seal two traits in the same module

This is due to #[sealed] attribute desugras into the hardcoded private name of a module.

The name should be unique per trait and must be derivable from the trait's name. Something like:

#[sealed]
pub trait MyTrait {}
// expands to:
// pub trait MyTrait: __my_trait::Sealed {}
// mod __my_trait { pub trait Sealed {} }

Do not run certain tests for certain versions

The most clear example would be const generics which were made "stable" in 1.51.0, as far as I know the crate should be able to work with earlier Rust versions.

Thus, ideally, the test would only run from 1.51 forwards and all others would run normally.

Cross-ref to #14 which is related but not the same

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.