Crate semigroup

Source
Expand description

Semigroup trait is useful

  • reading configs from multiple sources
  • statistically aggregation
  • fast range queries using segment tree

§Usage

[dependencies]
semigroup = { git = "https://github.com/hayas1/semigroup", features = ["derive", "monoid"] }

§Examples

§Reading configs from multiple sources

§With simple string annotation

use semigroup::{Annotate, Semigroup};
#[derive(Debug, Clone, PartialEq, Semigroup)]
#[semigroup(annotated, with = "semigroup::op::coalesce::Coalesce")]
pub struct Config<'a> {
    pub num: Option<u32>,
    pub str: Option<&'a str>,
    #[semigroup(with = "semigroup::op::overwrite::Overwrite")]
    pub boolean: bool,
}

let file = Config { num: Some(1), str: None, boolean: true }.annotated("File");
let env = Config { num: None, str: Some("ten"), boolean: false }.annotated("Env");
let cli = Config { num: Some(100), str: None, boolean: true }.annotated("Cli");

let config = file.semigroup(env).semigroup(cli);

assert_eq!(config.value(), &Config { num: Some(1), str: Some("ten"), boolean: true });
assert_eq!(config.annotation().num, "File");
assert_eq!(config.annotation().str, "Env");
assert_eq!(config.annotation().boolean, "Cli");

§With rich enum annotation

use semigroup::{Annotate, Semigroup};
#[derive(Debug, Clone, PartialEq, Semigroup)]
#[semigroup(annotated, with = "semigroup::op::coalesce::Coalesce")]
pub struct Config<'a> {
    pub num: Option<u32>,
    pub str: Option<&'a str>,
    #[semigroup(with = "semigroup::op::overwrite::Overwrite")]
    pub boolean: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Source {
    File,
    Env,
    Cli,
}

let file = Config { num: Some(1), str: None, boolean: true }.annotated(Source::File);
let env = Config { num: None, str: Some("ten"), boolean: false }.annotated(Source::Env);
let cli = Config { num: Some(100), str: None, boolean: true }.annotated(Source::Cli);

let config = file.semigroup(env).semigroup(cli);

assert_eq!(config.value(), &Config { num: Some(1), str: Some("ten"), boolean: true });
assert_eq!(config.annotation().num, Source::File);
assert_eq!(config.annotation().str, Source::Env);
assert_eq!(config.annotation().boolean, Source::Cli);

§Lazy Evaluation

§Reduce

use semigroup::{Annotate, Semigroup};
#[derive(Debug, Clone, PartialEq, Semigroup)]
#[semigroup(annotated, with = "semigroup::op::coalesce::Coalesce")]
pub struct Config<'a> {
    pub num: Option<u32>,
    pub str: Option<&'a str>,
    #[semigroup(with = "semigroup::op::overwrite::Overwrite")]
    pub boolean: bool,
}

let lazy = vec![
    Config { num: Some(1), str: None, boolean: true }.annotated("File"),
    Config { num: None, str: Some("ten"), boolean: false }.annotated("Env"),
    Config { num: Some(100), str: None, boolean: true }.annotated("Cli"),
];


let config = lazy.into_iter().reduce(|acc, item| acc.semigroup(item));

assert_eq!(config.as_ref().unwrap().value(), &Config { num: Some(1), str: Some("ten"), boolean: true });
assert_eq!(config.as_ref().unwrap().annotation().num, "File");
assert_eq!(config.as_ref().unwrap().annotation().str, "Env");
assert_eq!(config.as_ref().unwrap().annotation().boolean, "Cli");

§Fold with final default

use semigroup::{Annotate, Semigroup, SemigroupIterator};
#[derive(Debug, Clone, PartialEq, Semigroup)]
#[semigroup(annotated, with = "semigroup::op::coalesce::Coalesce")]
pub struct Config<'a> {
    pub num: Option<u32>,
    pub str: Option<&'a str>,
    #[semigroup(with = "semigroup::op::overwrite::Overwrite")]
    pub boolean: bool,
}

let lazy = vec![
    Config { num: Some(1), str: None, boolean: true }.annotated("File"),
    Config { num: None, str: None, boolean: false }.annotated("Env"),
    Config { num: Some(100), str: None, boolean: true }.annotated("Cli"),
];


let config = lazy.into_iter().fold_final(Config { num: Some(1000), str: Some("thousand"), boolean: true }.annotated("Default"));

assert_eq!(config.value(), &Config { num: Some(1), str: Some("thousand"), boolean: true });
assert_eq!(config.annotation().num, "File");
assert_eq!(config.annotation().str, "Default");
assert_eq!(config.annotation().boolean, "Default");

§Segment tree

Only available with the monoid feature

use semigroup::{Semigroup, Construction, segment_tree::SegmentTree, monoid::Monoid};
#[derive(
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash, Construction,
)]
struct Max(pub i32);
impl Semigroup for Max {
    fn op(base: Self, other: Self) -> Self {
        Max(std::cmp::max(base.0, other.0))
    }
}
impl Monoid for Max {
    fn unit() -> Self {
        Max(i32::MIN)
    }
}

let data = [2, -5, 122, -33, -12, 14, -55, 500, 3];
let mut max_tree: SegmentTree<_> = data.into_iter().map(Max).collect();
assert_eq!(max_tree.fold(3..6).0, 14);
max_tree.update_with(4, |Max(x)| Max(x + 1000));
assert_eq!(max_tree.fold(3..6).0, 988);

// #[test]
semigroup::assert_monoid!(&max_tree[..]);

§Documents

https://hayas1.github.io/semigroup/semigroup

§Testing

§Benchmarks

// TODO

§Coverage

https://hayas1.github.io/semigroup/semigroup/tarpaulin-report.html

Modules§

op

Structs§

Annotated
Reverse

Traits§

Annotate
AnnotatedSemigroup
Commutative
Semigroup
SemigroupDoubleEndedIterator
SemigroupIterator