rust_toolchain_file/
toml.rs

1#[cfg(test)]
2mod tests;
3
4use camino::{Utf8Path, Utf8PathBuf};
5
6/// A parser for the TOML based toolchain file format.
7pub struct Parser<'content> {
8    content: &'content [u8],
9}
10
11impl<'content> Parser<'content> {
12    /// Initialize a parser for the `&str` content.
13    pub fn new(content: &'content str) -> Self {
14        Self {
15            content: content.as_bytes(),
16        }
17    }
18
19    /// Initialize a parser.
20    pub fn from_slice(content: &'content [u8]) -> Self {
21        Self { content }
22    }
23}
24
25impl Parser<'_> {
26    pub fn parse(&self) -> Result<RustToolchainToml, ParserError> {
27        toml_edit::de::from_slice(self.content).map_err(ParserError::TomlParse)
28    }
29}
30
31#[derive(Debug, thiserror::Error, PartialEq)]
32pub enum ParserError {
33    #[error("Unable to parse toolchain file: {0}")]
34    TomlParse(toml_edit::de::Error),
35}
36
37#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
38pub struct RustToolchainToml {
39    toolchain: ToolchainSection,
40}
41
42impl RustToolchainToml {
43    pub fn toolchain(&self) -> &ToolchainSection {
44        &self.toolchain
45    }
46}
47
48#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
49#[serde(untagged)]
50pub enum ToolchainSection {
51    Path(ToolchainPath),
52    Spec(ToolchainSpec),
53}
54
55impl ToolchainSection {
56    pub fn path(&self) -> Option<&ToolchainPath> {
57        match self {
58            Self::Path(p) => Some(p),
59            _ => None,
60        }
61    }
62
63    pub fn spec(&self) -> Option<&ToolchainSpec> {
64        match self {
65            Self::Spec(ts) => Some(ts),
66            _ => None,
67        }
68    }
69}
70
71#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
72pub struct ToolchainSpec {
73    channel: Option<Channel>,
74    components: Option<Vec<Component>>,
75    targets: Option<Vec<Target>>,
76    profile: Option<Profile>,
77}
78
79impl ToolchainSpec {
80    pub fn channel(&self) -> Option<&Channel> {
81        self.channel.as_ref()
82    }
83
84    pub fn components(&self) -> Option<&[Component]> {
85        self.components.as_deref()
86    }
87
88    pub fn targets(&self) -> Option<&[Target]> {
89        self.targets.as_deref()
90    }
91
92    pub fn profile(&self) -> Option<&Profile> {
93        self.profile.as_ref()
94    }
95}
96
97#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
98pub struct ToolchainPath {
99    path: Utf8PathBuf,
100}
101
102impl ToolchainPath {
103    pub fn path(&self) -> &Utf8Path {
104        &self.path
105    }
106}
107
108#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
109pub struct Channel(String);
110
111impl Channel {
112    pub fn name(&self) -> &str {
113        &self.0
114    }
115}
116
117#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
118pub struct Component(String);
119
120impl Component {
121    pub fn name(&self) -> &str {
122        &self.0
123    }
124}
125
126#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
127pub struct Target(String);
128
129impl Target {
130    pub fn name(&self) -> &str {
131        &self.0
132    }
133}
134
135#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
136pub struct Profile(String);
137
138impl Profile {
139    pub fn name(&self) -> &str {
140        &self.0
141    }
142}