sphinx_rustdocgen/directives/
directive_options.rs

1use std::fmt::{Display, Formatter};
2use std::str::FromStr;
3
4use serde::Deserialize;
5use syn::Visibility;
6
7use crate::formats::{MdOption, RstOption};
8use crate::nodes::Node;
9
10/// Enum for the values of the :rust:struct:`DirectiveOption::Vis` option
11///
12/// The enum is ordered ``Pub < Crate < Pvt``, so it can be efficiently
13/// compared for filtering. Note that ordering here is opposite to that of the
14/// visibility itself.
15#[derive(Clone, Copy, Debug, Default, Deserialize, Ord, PartialOrd, Eq, PartialEq)]
16#[serde(rename_all = "lowercase")]
17pub(crate) enum DirectiveVisibility {
18    /// Public visibility
19    #[default]
20    Pub = 0,
21    /// Crate visibility
22    Crate = 1,
23    /// Private visibility
24    Pvt = 2,
25}
26
27impl DirectiveVisibility {
28    /// Determine the effective visibility for an item based on its visibility
29    /// or its parent's visibility.
30    ///
31    /// Args:
32    ///     :visibility: The item's visibility.
33    ///     :inherited_visibility: The visibility of the item's parent.
34    ///
35    /// Returns:
36    ///     The directive visibility applicable to the item.
37    pub(crate) fn effective_visibility(
38        visibility: &Visibility,
39        inherited_visibility: &Option<&Visibility>,
40    ) -> Self {
41        match visibility {
42            Visibility::Public(_) => DirectiveVisibility::Pub,
43            Visibility::Restricted(v) => {
44                let path = &v.path;
45                if path.segments.len() == 1 && path.segments.first().unwrap().ident == "crate" {
46                    DirectiveVisibility::Crate
47                }
48                else {
49                    DirectiveVisibility::Pvt
50                }
51            }
52            Visibility::Inherited => match inherited_visibility {
53                None => DirectiveVisibility::Pvt,
54                Some(v) => Self::effective_visibility(v, &None),
55            },
56        }
57    }
58}
59
60impl Display for DirectiveVisibility {
61    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
62        f.write_str(match self {
63            DirectiveVisibility::Pub => "pub",
64            DirectiveVisibility::Crate => "crate",
65            DirectiveVisibility::Pvt => "pvt",
66        })
67    }
68}
69
70impl From<&Visibility> for DirectiveVisibility {
71    fn from(value: &Visibility) -> Self {
72        Self::effective_visibility(value, &None)
73    }
74}
75
76impl FromStr for DirectiveVisibility {
77    type Err = String;
78
79    fn from_str(s: &str) -> Result<Self, Self::Err> {
80        let s = s.to_lowercase();
81        if s == "pub" {
82            Ok(DirectiveVisibility::Pub)
83        }
84        else if s == "crate" {
85            Ok(DirectiveVisibility::Crate)
86        }
87        else if s == "pvt" {
88            Ok(DirectiveVisibility::Pvt)
89        }
90        else {
91            Err(format!("Invalid value for visibility: {s}"))
92        }
93    }
94}
95
96/// The different index entry types.
97///
98/// This corresponds to the Python enum
99/// :py:class:`sphinxcontrib_rust.items.SphinxIndexEntryType`.
100#[derive(Copy, Clone, Debug)]
101#[repr(i8)]
102pub(crate) enum IndexEntryType {
103    None = -1,
104    Normal = 0,
105    WithSubEntries = 1,
106    SubEntry = 2,
107}
108
109/// Enum to represent the various options for the directives.
110///
111/// The enum implements the :rust:trait:`RstOption` and :rust:trait:`MdOption`
112/// traits for easily converting the options to required text.
113#[derive(Clone, Debug)]
114pub(crate) enum DirectiveOption {
115    /// The ``:index:`` option
116    Index(IndexEntryType),
117    /// The ``:vis:`` option.
118    Vis(DirectiveVisibility),
119    /// The ``:layout:`` option.
120    Layout(Vec<Node>),
121    /// The ``:toc:`` option.
122    Toc(String),
123}
124
125impl RstOption for DirectiveOption {
126    fn get_rst_text(&self, indent: &str) -> Option<String> {
127        Some(match self {
128            DirectiveOption::Index(i) => {
129                format!("{indent}:index: {}", *i as i8)
130            }
131            DirectiveOption::Vis(v) => {
132                format!("{indent}:vis: {v}")
133            }
134            DirectiveOption::Toc(t) => {
135                format!("{indent}:toc: {t}")
136            }
137            DirectiveOption::Layout(lines) => {
138                format!("{indent}:layout: {}", serde_json::to_string(lines).unwrap())
139            }
140        })
141    }
142}
143
144impl MdOption for DirectiveOption {
145    fn get_md_text(&self) -> Option<String> {
146        Some(match self {
147            DirectiveOption::Index(i) => {
148                format!(":index: {}", *i as i8)
149            }
150            DirectiveOption::Vis(v) => {
151                format!(":vis: {v}")
152            }
153            DirectiveOption::Toc(t) => {
154                format!(":toc: {t}")
155            }
156            DirectiveOption::Layout(lines) => {
157                format!(":layout: {}", serde_json::to_string(lines).unwrap())
158            }
159        })
160    }
161}