Skip to content

Instantly share code, notes, and snippets.

@EarlGray
Created June 20, 2023 22:10
Show Gist options
  • Save EarlGray/7e9720bee92f67d34455366bc4911538 to your computer and use it in GitHub Desktop.
Save EarlGray/7e9720bee92f67d34455366bc4911538 to your computer and use it in GitHub Desktop.
encoding state of a Builder into a const generic bitmask
/// This is an example of encoding state of a Builder
/// into a const generic bitmask. [`PipelineBuilder`]
/// only allows `.build()` when all of the fields have
/// been set.
/// This requires a scary nightly feature that rustc
/// marks with a stark warning:
/// ```ignore
/// the feature `generic_const_exprs` is incomplete
/// and may not be safe to use and/or cause compiler crashes
/// see issue #76560 <https://github.com/rust-lang/rust/issues/76560>
/// for more information
/// ```
#![feature(generic_const_exprs)]
pub type Source = &'static str;
pub type Sink = &'static str;
pub type Processor = &'static str;
#[allow(unused)]
pub struct Pipeline {
source: Source,
processor: Processor,
sink: Sink,
}
pub struct PipelineBuilder<const M: u8> {
source: Option<Source>,
processor: Option<Processor>,
sink: Option<Sink>,
}
impl Default for PipelineBuilder<0> {
fn default() -> Self {
PipelineBuilder { source: None, processor: None, sink: None }
}
}
impl<const M: u8> PipelineBuilder<M> {
pub fn set_source(self, source: Source) -> PipelineBuilder<{1 | M}> {
let PipelineBuilder { processor, sink , ..} = self;
PipelineBuilder { source: source.into(), processor, sink }
}
}
impl<const M: u8> PipelineBuilder<M> {
pub fn set_processor(self, processor: Processor) -> PipelineBuilder<{2 | M}> {
let PipelineBuilder { source, sink , ..} = self;
PipelineBuilder { source, processor: processor.into(), sink }
}
}
impl<const M: u8> PipelineBuilder<M> {
pub fn set_sink(self, sink: Sink) -> PipelineBuilder<{4 | M}> {
let PipelineBuilder { source, processor , ..} = self;
PipelineBuilder { source, processor, sink: sink.into() }
}
}
impl PipelineBuilder<7> {
pub fn build(self) -> Pipeline {
match self {
PipelineBuilder {
source: Some(source),
processor: Some(processor),
sink: Some(sink),
} => Pipeline { source, processor, sink },
_ => unreachable!(),
}
}
}
#[cfg(test)]
mod tests {
use super::PipelineBuilder;
#[test]
fn test() {
let p = PipelineBuilder::default()
.set_source("source")
.set_processor("proc")
.set_sink("sink")
.build();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment