mod renderers;
use alloc::string::{String, ToString};
use core::fmt::Display;
pub use renderers::Renderer;
mod direction;
pub use direction::Direction;
mod theme;
pub use theme::Theme;
mod look;
pub use look::Look;
use crate::{
errors::ConfigError,
traits::{Configuration, ConfigurationBuilder},
};
#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct GenericConfiguration {
title: Option<String>,
renderer: Renderer,
direction: Direction,
theme: Theme,
look: Look,
}
impl Configuration for GenericConfiguration {
type Builder = GenericConfigurationBuilder;
fn title(&self) -> Option<&str> {
self.title.as_deref()
}
fn renderer(&self) -> Renderer {
self.renderer
}
fn direction(&self) -> Direction {
self.direction
}
fn theme(&self) -> Theme {
self.theme
}
fn look(&self) -> Look {
self.look
}
}
impl Display for GenericConfiguration {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
writeln!(f, "---")?;
writeln!(f, "config:")?;
writeln!(f, " layout: {}", self.renderer)?;
writeln!(f, " theme: {}", self.theme)?;
writeln!(f, " look: {}", self.look)?;
if let Some(title) = &self.title {
writeln!(f, "title: {title}")?;
}
writeln!(f, "---")?;
Ok(())
}
}
#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct GenericConfigurationBuilder {
title: Option<String>,
renderer: Renderer,
direction: Direction,
theme: Theme,
look: Look,
}
impl TryFrom<GenericConfigurationBuilder> for GenericConfiguration {
type Error = ConfigError;
fn try_from(builder: GenericConfigurationBuilder) -> Result<Self, Self::Error> {
Ok(GenericConfiguration {
title: builder.title,
renderer: builder.renderer,
direction: builder.direction,
theme: builder.theme,
look: builder.look,
})
}
}
impl ConfigurationBuilder for GenericConfigurationBuilder {
type Configuration = GenericConfiguration;
type Error = ConfigError;
fn build(self) -> Result<Self::Configuration, Self::Error> {
self.try_into()
}
fn title<S: ToString>(mut self, title: S) -> Result<Self, Self::Error> {
let title = title.to_string();
if title.is_empty() {
return Err(ConfigError::EmptyTitle);
}
self.title = Some(title);
Ok(self)
}
fn renderer(mut self, renderer: Renderer) -> Self {
self.renderer = renderer;
self
}
fn direction(mut self, direction: Direction) -> Self {
self.direction = direction;
self
}
}
impl GenericConfigurationBuilder {
#[must_use]
pub fn theme(mut self, theme: Theme) -> Self {
self.theme = theme;
self
}
#[must_use]
pub fn look(mut self, look: Look) -> Self {
self.look = look;
self
}
}
#[cfg(test)]
mod tests {
use alloc::format;
use super::*;
#[test]
fn test_generic_configuration_display() {
let config = GenericConfiguration::default();
assert_eq!(
format!("{config}"),
"---\nconfig:\n layout: dagre\n theme: default\n look: classic\n---\n"
);
}
#[test]
fn test_generic_configuration_builder() -> Result<(), ConfigError> {
let config = GenericConfigurationBuilder::default()
.title("My Diagram")?
.renderer(Renderer::EclipseLayoutKernel)
.direction(Direction::TopToBottom)
.theme(Theme::Forest)
.look(Look::HandDrawn)
.build()?;
assert_eq!(config.title(), Some("My Diagram"));
assert_eq!(config.renderer(), Renderer::EclipseLayoutKernel);
assert_eq!(config.direction(), Direction::TopToBottom);
assert_eq!(config.theme(), Theme::Forest);
assert_eq!(config.look(), Look::HandDrawn);
Ok(())
}
#[test]
fn test_generic_configuration_builder_errors() {
let builder = GenericConfigurationBuilder::default();
assert!(matches!(builder.title(""), Err(ConfigError::EmptyTitle)));
}
}