mod error;
mod project;
use std::fmt::{self, Display};
use std::str::FromStr;
use toml_edit::{DocumentMut, Item, Table, value};
use crate::repository::RepoSpec;
pub use self::error::Error;
pub use self::project::{Project, ProjectMut};
#[derive(Clone, Debug)]
pub struct Config(DocumentMut);
impl Config {
pub fn new(name: impl Into<String>) -> Self {
let mut document = DocumentMut::new();
document.insert(
"project",
Item::Table({
let mut table = Table::new();
table.insert("name", value(name.into()));
table
}),
);
Self(document)
}
pub fn project_name(&self) -> &str {
self.project().name()
}
pub fn project_description(&self) -> Option<&str> {
self.project().description()
}
pub fn set_project_description(&mut self, description: impl Into<String>) -> &mut Self {
self.project_mut().set_description(description);
self
}
pub fn with_project_description(mut self, description: impl Into<String>) -> Self {
self.set_project_description(description);
self
}
pub fn project_repository(&self) -> Option<RepoSpec> {
self.project().repository()
}
pub fn set_project_repository(&mut self, repository: impl Into<RepoSpec>) -> &mut Self {
self.project_mut().set_repository(repository);
self
}
pub fn with_project_repository(mut self, repository: impl Into<RepoSpec>) -> Self {
self.set_project_repository(repository);
self
}
pub fn project_authors(&self) -> impl Iterator<Item = &str> {
self.project().authors()
}
pub fn set_project_authors(&mut self, authors: impl IntoIterator<Item = String>) -> &mut Self {
self.project_mut().set_authors(authors);
self
}
pub fn with_project_authors(mut self, authors: impl IntoIterator<Item = String>) -> Self {
self.set_project_authors(authors);
self
}
pub fn project(&self) -> Project<'_> {
Project::from_table(
self.0
.get("project")
.and_then(Item::as_table_like)
.expect("project"),
)
.expect("project table")
}
pub fn project_mut(&mut self) -> ProjectMut<'_> {
ProjectMut::from_table(
self.0
.get_mut("project")
.and_then(Item::as_table_like_mut)
.expect("project"),
)
.expect("project table")
}
}
impl Config {
pub(crate) fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
std::str::from_utf8(bytes)?.parse()
}
}
impl Display for Config {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl PartialEq for Config {
fn eq(&self, other: &Self) -> bool {
self.0.to_string() == other.0.to_string()
}
}
impl Eq for Config {}
impl FromStr for Config {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let document: DocumentMut = s.parse()?;
Project::from_table(
document
.get("project")
.and_then(Item::as_table_like)
.ok_or(Error::Invalid)?,
)
.ok_or(Error::Invalid)?;
Ok(Self(document))
}
}
#[cfg(test)]
mod tests {
use crate::repository::RepoSpec;
use super::Config;
#[test]
fn test_builder() {
let config = Config::new("example")
.with_project_description("An example project.")
.with_project_repository("ploys/example".parse::<RepoSpec>().unwrap());
assert_eq!(config.project_name(), "example");
assert_eq!(config.project_description().unwrap(), "An example project.");
assert_eq!(
config.project_repository().unwrap(),
"ploys/example".parse::<RepoSpec>().unwrap()
);
let expected = indoc::indoc! {r#"
[project]
name = "example"
description = "An example project."
repository = "ploys/example"
"#};
assert_eq!(config.to_string(), expected);
}
}