pub mod channel;
pub mod error;
pub mod forgiving;
pub mod interval;
pub mod normalize;
pub mod pipeline;
pub mod plugin;
pub mod size;
use std::{fmt, str::FromStr};
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::{Map, Value};
pub use crate::{
channel::{ChannelId, ChannelTarget, HostBuilder},
error::{PluginError, Result},
forgiving::Forgiving,
interval::{Interval, ParseIntervalError},
normalize::{canonical, normalize},
pipeline::{Chain, Emitted, Pipeline, Registry, Segment},
plugin::{
BuildCtx, Ctx, EffectSink, Emission, Emit, Execution, ExternalStage, LogLevel,
PipelineMeta, Plugin, PluginFactory, Stage, StageInfo, StderrMode,
},
size::{ByteSize, ParseSizeError},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum Direction {
#[serde(alias = "forward", alias = "src-to-sink", alias = "source-to-sink")]
SourceToSink,
#[serde(alias = "reverse", alias = "sink-to-src", alias = "sink-to-source")]
SinkToSource,
}
impl Direction {
pub const ALL: [Direction; 2] = [Direction::SourceToSink, Direction::SinkToSource];
#[must_use]
pub fn flip(self) -> Self {
match self {
Direction::SourceToSink => Direction::SinkToSource,
Direction::SinkToSource => Direction::SourceToSink,
}
}
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
Direction::SourceToSink => "source-to-sink",
Direction::SinkToSource => "sink-to-source",
}
}
}
impl fmt::Display for Direction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum DirectionSpec {
SourceToSink,
SinkToSource,
#[default]
Both,
}
impl<'de> Deserialize<'de> for DirectionSpec {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
let raw = String::deserialize(deserializer)?;
raw.parse().map_err(serde::de::Error::custom)
}
}
impl DirectionSpec {
#[must_use]
pub fn contains(self, direction: Direction) -> bool {
matches!(
(self, direction),
(DirectionSpec::Both, _)
| (DirectionSpec::SourceToSink, Direction::SourceToSink)
| (DirectionSpec::SinkToSource, Direction::SinkToSource)
)
}
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
DirectionSpec::SourceToSink => "source-to-sink",
DirectionSpec::SinkToSource => "sink-to-source",
DirectionSpec::Both => "both",
}
}
}
impl fmt::Display for DirectionSpec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseDirectionError(pub String);
impl fmt::Display for ParseDirectionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"unknown direction {:?}; expected one of: source-to-sink, sink-to-source, both",
self.0
)
}
}
impl std::error::Error for ParseDirectionError {}
impl FromStr for DirectionSpec {
type Err = ParseDirectionError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match normalize(s.trim()).as_str() {
"sourcetosink" | "srctosink" | "forward" | "fwd" | "source" | "src" | "out" => {
Ok(DirectionSpec::SourceToSink)
}
"sinktosource" | "sinktosrc" | "reverse" | "rev" | "sink" | "in" => {
Ok(DirectionSpec::SinkToSource)
}
"both" | "bidi" | "bidirectional" | "duplex" | "all" => Ok(DirectionSpec::Both),
_ => Err(ParseDirectionError(s.to_string())),
}
}
}
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct PluginSpec {
#[serde(alias = "plugin", alias = "use")]
pub name: String,
#[serde(default)]
pub direction: DirectionSpec,
#[serde(default, rename = "as")]
pub alias: Option<String>,
#[serde(default)]
pub detach: Option<bool>,
#[serde(flatten, default)]
pub config: Map<String, Value>,
}
impl PluginSpec {
pub fn new(name: impl Into<String>, direction: DirectionSpec) -> Self {
Self {
name: name.into(),
direction,
alias: None,
detach: None,
config: Map::new(),
}
}
#[must_use]
pub fn named(mut self, alias: impl Into<String>) -> Self {
self.alias = Some(alias.into());
self
}
#[must_use]
pub fn detached(mut self, detach: bool) -> Self {
self.detach = Some(detach);
self
}
#[must_use]
pub fn with(mut self, key: impl Into<String>, value: impl Into<Value>) -> Self {
self.config.insert(key.into(), value.into());
self
}
pub fn set(&mut self, key: impl Into<String>, value: impl Into<Value>) -> &mut Self {
self.config.insert(key.into(), value.into());
self
}
}
impl fmt::Display for PluginSpec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.alias {
Some(alias) => write!(f, "{} ({}:{})", alias, self.name, self.direction),
None => write!(f, "{}:{}", self.name, self.direction),
}
}
}