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}