marker_api/sem/
item.rs

1use std::marker::PhantomData;
2
3use crate::common::ItemId;
4
5/// The declared visibility of an item or field.
6///
7/// ```
8/// // An item without a visibility
9/// fn moon() {}
10///
11/// // A public item
12/// pub fn sun() {}
13///
14/// // An item with a restricted scope
15/// pub(crate) fn star() {}
16///
17/// pub trait Planet {
18///     // An item without a visibility. But it still has the semantic visibility
19///     // of `pub` as this is inside a trait declaration.
20///     fn mass();
21/// }
22/// ```
23#[repr(C)]
24#[derive(Debug)]
25#[cfg_attr(feature = "driver-api", derive(typed_builder::TypedBuilder))]
26pub struct Visibility<'ast> {
27    #[cfg_attr(feature = "driver-api", builder(setter(skip), default))]
28    _lifetime: PhantomData<&'ast ()>,
29    kind: VisibilityKind,
30}
31
32impl<'ast> Visibility<'ast> {
33    /// Returns `true` if the item is public, meaning that it can be visible outside
34    /// the crate.
35    ///
36    /// ```
37    /// // This returns `true`
38    /// pub fn unicorn() {}
39    ///
40    /// // This returns `false`, since the visibility is restricted to a specified path.
41    /// pub(crate) fn giraffe() {}
42    ///
43    /// // This returns `false`, since the visibility is not defined
44    /// fn dragon() {}
45    ///
46    /// pub trait MythicalCreature {
47    ///     // This returns `true`, since the default visibility for trait items is public
48    ///     fn name() -> &'static str;
49    /// }
50    /// ```
51    pub fn is_pub(&self) -> bool {
52        self.scope().is_none()
53    }
54
55    /// Returns `true` if the item is visible in the entire crate. This is
56    /// the case for items declared as `pub(crate)`. Items declared in the root
57    /// module of the crate or specify the path of the root module are also
58    /// scoped to the entire crate.
59    ///
60    /// ```
61    /// // lib.rs
62    ///
63    /// mod example_1 {
64    ///     // Returns `false` since it's only visible in `crate::example_1`
65    ///     fn foo() {}
66    ///
67    ///     // Returns `false` since it's only visible in `crate::example_1`
68    ///     pub(in crate::example_1) fn bar() {}
69    ///
70    ///     // Returns `true` as the visibility is restricted to the root of the crate.
71    ///     pub(crate) fn baz() {}
72    ///
73    ///     // Returns `true` as the visibility is restricted to `super` which is the
74    ///     // root of the crate.
75    ///     pub(super) fn boo() {}
76    /// }
77    ///
78    /// // Returns `true` since this item is at the root of the crate and the default
79    /// // visibility is therefore `pub(crate)`
80    /// fn example_in_root() {}
81    ///
82    /// # fn main() {}
83    /// ```
84    pub fn is_crate_scoped(&self) -> bool {
85        matches!(self.kind, VisibilityKind::Crate(_) | VisibilityKind::DefaultCrate(_))
86    }
87
88    /// Returns `true` if a visibility is the default visibility, meaning that it wasn't
89    /// declared.
90    pub fn is_default(&self) -> bool {
91        match self.kind {
92            VisibilityKind::DefaultPub | VisibilityKind::DefaultCrate(_) | VisibilityKind::Default(_) => true,
93            VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Path(_) => false,
94        }
95    }
96
97    /// Returns the [`ItemId`] of the module that this item or field is visible in.
98    /// It will return `None`, if the item is public, as the visibility extends past
99    /// the root module of the crate.
100    ///
101    /// This function also works for items which have the default visibility, of the
102    /// module they are declared in.
103    ///
104    /// ```
105    /// // lib.rs
106    ///
107    /// mod scope {
108    ///     // Returns `None` since this is even visible outside the current crate
109    ///     pub fn turtle() {}
110    ///     
111    ///     // Returns the `ItemId` of the root module of the crate
112    ///     pub(crate) fn shark() {}
113    ///
114    ///     // Returns the `ItemId` of the module it is declared in, in this case `crate::scope`
115    ///     fn dolphin() {}
116    /// }
117    /// ```
118    pub fn scope(&self) -> Option<ItemId> {
119        match self.kind {
120            VisibilityKind::Path(id)
121            | VisibilityKind::Crate(id)
122            | VisibilityKind::DefaultCrate(id)
123            | VisibilityKind::Default(id) => Some(id),
124            VisibilityKind::Public | VisibilityKind::DefaultPub => None,
125        }
126    }
127
128    // FIXME(xFrednet): Implement functions to check if an item is visible from a
129    // given `ItemId`. This can be done once rust-marker/marker#242 is implemented.
130}
131
132#[derive(Debug)]
133#[allow(clippy::exhaustive_enums)]
134#[cfg_attr(feature = "driver-api", visibility::make(pub))]
135enum VisibilityKind {
136    /// The item is declared as `pub` without any restrictions
137    Public,
138    /// For items which are `pub` by default, like trait functions or enum variants
139    DefaultPub,
140    /// The visibility is restricted to the root module of the crate. The [`ItemId`]
141    /// identifies the root module.
142    Crate(ItemId),
143    /// The items doesn't have a declared visibility. The default is visible in the
144    /// entire crate. The [`ItemId`] identifies the root module.
145    DefaultCrate(ItemId),
146    /// The visibility is restricted to a specific module using `pub(<path>)`.
147    /// The module, targeted by the path is identified by the [`ItemId`].
148    /// The `pub(crate)` has it's own variant in this struct.
149    Path(ItemId),
150    /// The items doesn't have a declared visibility. The default is restricted to
151    /// a module, identified by the stored [`ItemId`]
152    Default(ItemId),
153}