use crate::components::{Rgb, Text};
use std::cmp::Ordering;
#[derive(Clone, Default)]
pub enum FacetScales {
#[default]
Fixed,
Free,
FreeX,
FreeY,
}
#[derive(Clone, Default)]
pub struct FacetConfig {
pub rows: Option<usize>,
pub cols: Option<usize>,
pub scales: FacetScales,
pub h_gap: Option<f64>,
pub v_gap: Option<f64>,
pub title_style: Option<Text>,
pub sorter: Option<fn(&str, &str) -> Ordering>,
pub highlight_facet: bool,
pub unhighlighted_color: Option<Rgb>,
}
impl FacetConfig {
pub fn new() -> Self {
Self::default()
}
pub fn rows(mut self, rows: usize) -> Self {
if rows == 0 {
panic!("rows must be greater than 0");
}
self.rows = Some(rows);
self
}
pub fn cols(mut self, cols: usize) -> Self {
if cols == 0 {
panic!("cols must be greater than 0");
}
self.cols = Some(cols);
self
}
pub fn scales(mut self, scales: FacetScales) -> Self {
self.scales = scales;
self
}
pub fn h_gap(mut self, gap: f64) -> Self {
if !gap.is_finite() || gap < 0.0 {
panic!("h_gap must be a finite non-negative number");
}
self.h_gap = Some(gap);
self
}
pub fn v_gap(mut self, gap: f64) -> Self {
if !gap.is_finite() || gap < 0.0 {
panic!("v_gap must be a finite non-negative number");
}
self.v_gap = Some(gap);
self
}
pub fn title_style<T: Into<Text>>(mut self, style: T) -> Self {
self.title_style = Some(style.into());
self
}
pub fn sorter(mut self, f: fn(&str, &str) -> Ordering) -> Self {
self.sorter = Some(f);
self
}
pub fn highlight_facet(mut self, highlight: bool) -> Self {
self.highlight_facet = highlight;
self
}
pub fn unhighlighted_color(mut self, color: Rgb) -> Self {
self.unhighlighted_color = Some(color);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default() {
let fc = FacetConfig::new();
assert!(fc.rows.is_none());
assert!(fc.cols.is_none());
assert!(fc.h_gap.is_none());
assert!(fc.v_gap.is_none());
assert!(fc.title_style.is_none());
assert!(fc.sorter.is_none());
assert!(!fc.highlight_facet);
assert!(fc.unhighlighted_color.is_none());
}
#[test]
fn test_rows_valid() {
let fc = FacetConfig::new().rows(2);
assert_eq!(fc.rows, Some(2));
}
#[test]
#[should_panic(expected = "rows must be greater than 0")]
fn test_rows_zero_panics() {
FacetConfig::new().rows(0);
}
#[test]
fn test_cols_valid() {
let fc = FacetConfig::new().cols(3);
assert_eq!(fc.cols, Some(3));
}
#[test]
#[should_panic(expected = "cols must be greater than 0")]
fn test_cols_zero_panics() {
FacetConfig::new().cols(0);
}
#[test]
fn test_h_gap_valid() {
let fc = FacetConfig::new().h_gap(0.05);
assert!((fc.h_gap.unwrap() - 0.05).abs() < 1e-6);
}
#[test]
#[should_panic(expected = "h_gap must be a finite non-negative number")]
fn test_h_gap_negative_panics() {
FacetConfig::new().h_gap(-0.1);
}
#[test]
#[should_panic(expected = "h_gap must be a finite non-negative number")]
fn test_h_gap_nan_panics() {
FacetConfig::new().h_gap(f64::NAN);
}
#[test]
fn test_v_gap_valid() {
let fc = FacetConfig::new().v_gap(0.1);
assert!((fc.v_gap.unwrap() - 0.1).abs() < 1e-6);
}
#[test]
#[should_panic(expected = "v_gap must be a finite non-negative number")]
fn test_v_gap_negative_panics() {
FacetConfig::new().v_gap(-0.5);
}
}