use crate::format::StreamFormat;
use crate::property::PropertyScope;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum StreamDirection {
Input,
Output,
}
impl StreamDirection {
#[inline]
#[must_use]
pub const fn as_property_value(self) -> u32 {
match self {
Self::Input => 1,
Self::Output => 0,
}
}
#[inline]
#[must_use]
pub const fn from_property_value(value: u32) -> Self {
if value == 0 {
Self::Output
} else {
Self::Input
}
}
#[inline]
#[must_use]
pub const fn scope(self) -> PropertyScope {
match self {
Self::Input => PropertyScope::INPUT,
Self::Output => PropertyScope::OUTPUT,
}
}
#[inline]
#[must_use]
pub const fn opposite(self) -> Self {
match self {
Self::Input => Self::Output,
Self::Output => Self::Input,
}
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct StreamSpec {
direction: StreamDirection,
starting_channel: u32,
format: StreamFormat,
}
impl StreamSpec {
#[inline]
#[must_use]
pub const fn input(format: StreamFormat) -> Self {
Self {
direction: StreamDirection::Input,
starting_channel: 1,
format,
}
}
#[inline]
#[must_use]
pub const fn output(format: StreamFormat) -> Self {
Self {
direction: StreamDirection::Output,
starting_channel: 1,
format,
}
}
#[inline]
#[must_use]
pub const fn with_starting_channel(mut self, channel: u32) -> Self {
self.starting_channel = channel;
self
}
#[inline]
#[must_use]
pub const fn with_format(mut self, format: StreamFormat) -> Self {
self.format = format;
self
}
#[inline]
#[must_use]
pub const fn direction(&self) -> StreamDirection {
self.direction
}
#[inline]
#[must_use]
pub const fn starting_channel(&self) -> u32 {
self.starting_channel
}
#[inline]
#[must_use]
pub const fn format(&self) -> StreamFormat {
self.format
}
#[inline]
#[must_use]
pub const fn channels(&self) -> u32 {
self.format.channels()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn direction_property_values_match_core_audio() {
assert_eq!(StreamDirection::Input.as_property_value(), 1);
assert_eq!(StreamDirection::Output.as_property_value(), 0);
}
#[test]
fn direction_round_trips_through_property_value() {
assert_eq!(
StreamDirection::from_property_value(1),
StreamDirection::Input
);
assert_eq!(
StreamDirection::from_property_value(0),
StreamDirection::Output
);
assert_eq!(
StreamDirection::from_property_value(99),
StreamDirection::Input
);
}
#[test]
fn direction_scopes_and_opposites() {
assert_eq!(StreamDirection::Input.scope(), PropertyScope::INPUT);
assert_eq!(StreamDirection::Output.scope(), PropertyScope::OUTPUT);
assert_eq!(StreamDirection::Input.opposite(), StreamDirection::Output);
assert_eq!(StreamDirection::Output.opposite(), StreamDirection::Input);
}
#[test]
fn input_stream_defaults() {
let s = StreamSpec::input(StreamFormat::float32(48_000.0, 2));
assert_eq!(s.direction(), StreamDirection::Input);
assert_eq!(s.starting_channel(), 1);
assert_eq!(s.channels(), 2);
assert!(s.format().is_canonical());
}
#[test]
fn output_stream_defaults() {
let s = StreamSpec::output(StreamFormat::float32(44_100.0, 1));
assert_eq!(s.direction(), StreamDirection::Output);
assert_eq!(s.starting_channel(), 1);
assert_eq!(s.channels(), 1);
}
#[test]
fn builder_setters_apply() {
let s = StreamSpec::output(StreamFormat::float32(48_000.0, 2))
.with_starting_channel(3)
.with_format(StreamFormat::float32(96_000.0, 4));
assert_eq!(s.starting_channel(), 3);
assert_eq!(s.format().sample_rate(), 96_000.0);
assert_eq!(s.channels(), 4);
}
}