use std::path::{Path, PathBuf};
use std::str::FromStr;
#[cfg(test)]
mod tests;
pub struct Parser<'content> {
content: &'content str,
strict: bool,
}
impl<'content> Parser<'content> {
pub fn new(content: &'content str) -> Self {
Self {
content,
strict: false,
}
}
pub fn strict(content: &'content str) -> Self {
Self {
content,
strict: true,
}
}
}
impl Parser<'_> {
pub fn parse(&self) -> Result<LegacyToolchainFile, ParserError> {
if self.strict && !self.content.is_ascii() {
return Err(ParserError::InvalidEncodingStrict);
}
let content = self.content.trim();
if content.is_empty() {
return Err(ParserError::IsEmpty);
}
let line_count = content.lines().count();
if line_count != 1 {
return Err(ParserError::TooManyLines(line_count));
}
let channel = if Path::new(content).is_absolute() {
LegacyChannel::Path(content.into())
} else {
LegacyChannel::Spec(content.to_string())
};
Ok(LegacyToolchainFile { channel })
}
}
#[derive(Debug, thiserror::Error, PartialEq)]
pub enum ParserError {
#[error("Unable to parse legacy toolchain file: toolchain file was empty")]
IsEmpty,
#[error("Encountered invalid encoding while parsing legacy rust-toolchain file. The expected encoding to be US-ASCII, and lenient encoding was disabled.")]
InvalidEncodingStrict,
#[error("Expected a single line containing the toolchain specifier but found '{0}' lines.")]
TooManyLines(usize),
}
#[derive(Debug, PartialEq)]
pub struct LegacyToolchainFile {
channel: LegacyChannel,
}
impl LegacyToolchainFile {
pub fn new(channel: LegacyChannel) -> Self {
Self { channel }
}
}
impl FromStr for LegacyToolchainFile {
type Err = ParserError;
fn from_str(content: &str) -> Result<Self, Self::Err> {
let parser = Parser::new(content);
parser.parse()
}
}
impl LegacyToolchainFile {
pub fn channel(&self) -> &LegacyChannel {
&self.channel
}
pub fn path(&self) -> Option<&Path> {
match self.channel {
LegacyChannel::Path(ref p) => Some(p.as_path()),
_ => None,
}
}
pub fn spec(&self) -> Option<&str> {
match self.channel {
LegacyChannel::Spec(ref p) => Some(p.as_str()),
_ => None,
}
}
}
#[derive(Debug, PartialEq)]
pub enum LegacyChannel {
Path(PathBuf),
Spec(String),
}