Skip to content

Commit

Permalink
Review visibility and add documents.
Browse files Browse the repository at this point in the history
  • Loading branch information
yotarok committed Oct 8, 2023
1 parent a812b9d commit a9c16a0
Show file tree
Hide file tree
Showing 4 changed files with 333 additions and 21 deletions.
55 changes: 52 additions & 3 deletions src/coding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ thread_local! {
}

/// Finds the best configuration for encoding samples and returns a `Frame`.
pub fn encode_frame(
fn encode_frame(
config: &config::Encoder,
framebuf: &FrameBuf,
offset: usize,
Expand All @@ -540,7 +540,34 @@ pub fn encode_frame(
ret
}

/// A variant of `encode_frame` that generates a frame in fixed-size mode.
/// Encodes `FrameBuf` to `Frame`.
///
/// # Examples
///
/// ```
/// # use flacenc::test_helper::*;
/// # use flacenc::*;
/// use flacenc::config;
/// use flacenc::component::StreamInfo;
/// use flacenc::source::{Context, FrameBuf, MemSource, Source};
///
/// let (signal_len, block_size, channels, sample_rate) = (32000, 160, 2, 16000);
/// let signal = constant_plus_noise(signal_len * channels, 0, 10000);
/// let bits_per_sample = 16;
///
/// let mut source = MemSource::from_samples(&signal, channels, bits_per_sample, sample_rate);
/// let mut fb = FrameBuf::with_size(channels, block_size);
/// let mut ctx = Context::new(bits_per_sample, channels);
/// let stream_info = StreamInfo::new(sample_rate, channels, bits_per_sample);
/// assert!(source.read_samples(&mut fb, &mut ctx).is_ok());
///
/// let frame = encode_fixed_size_frame(
/// &config::Encoder::default(), // block-size in config will be overridden.
/// &fb,
/// 0,
/// &stream_info
/// );
/// ```
pub fn encode_fixed_size_frame(
config: &config::Encoder,
framebuf: &FrameBuf,
Expand All @@ -559,6 +586,28 @@ pub fn encode_fixed_size_frame(
/// # Errors
///
/// This function returns `SourceError` when it failed to read samples from `src`.
///
/// # Panics
///
/// This function panics only by an internal error.
///
/// # Examples
///
/// ```
/// # use flacenc::test_helper::*;
/// # use flacenc::*;
/// use flacenc::config;
/// use flacenc::source::MemSource;
///
/// let (signal_len, block_size, channels, sample_rate) = (32000, 160, 2, 16000);
/// let signal = constant_plus_noise(signal_len * channels, 0, 10000);
/// let bits_per_sample = 16;
/// let source = MemSource::from_samples(&signal, channels, bits_per_sample, sample_rate);
/// let result = encode_with_fixed_block_size(
/// &config::Encoder::default(), source, block_size
/// );
/// assert!(result.is_ok());
/// ```
pub fn encode_with_fixed_block_size<T: Source>(
config: &config::Encoder,
mut src: T,
Expand All @@ -581,7 +630,7 @@ pub fn encode_with_fixed_block_size<T: Source>(
let frame = encode_fixed_size_frame(
config,
&framebuf,
context.current_frame_number(),
context.current_frame_number().unwrap(),
stream.stream_info(),
);
stream.add_frame(frame);
Expand Down
112 changes: 106 additions & 6 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use super::bitsink::BitSink;

/// Error type that will never happen.
///
/// This is a tentative solution while waiting
/// This is a tentative solution while waiting for
/// [`never-type`](https://github.com/rust-lang/rust/issues/35121) feature to
/// be stabilized.
#[derive(Clone, Copy, Debug)]
Expand All @@ -38,14 +38,16 @@ impl std::fmt::Display for Never {
impl std::error::Error for Never {}

/// Enum of errors that can be returned in the encoder.
#[derive(Clone)]
#[derive(Clone, Eq, Hash, PartialEq)]
#[allow(clippy::module_name_repetitions)]
pub enum OutputError<S>
where
S: BitSink,
S::Error: std::error::Error,
{
/// A parameter in a component doesn't fit in a format.
Range(RangeError),
/// I/O error propagated from `BitSink`.
Sink(S::Error),
}

Expand Down Expand Up @@ -119,7 +121,8 @@ where
}
}

#[derive(Clone, Debug)]
/// Error emitted when a parameter is out of the expected range.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[allow(clippy::module_name_repetitions)]
pub struct RangeError {
var: String,
Expand All @@ -129,7 +132,8 @@ pub struct RangeError {

/// Error object returned when a variable is out of supported range.
impl RangeError {
pub fn from_display<T>(var: &str, reason: &str, actual: &T) -> Self
/// Makes range error from `actual: impl Display` that is out of range.
pub(crate) fn from_display<T>(var: &str, reason: &str, actual: &T) -> Self
where
T: fmt::Display,
{
Expand Down Expand Up @@ -157,22 +161,49 @@ impl fmt::Display for RangeError {
}
}

/// Error object returned when data integrity verification failed.
#[derive(Debug, Hash)]
/// Error object returned when config integrity verification failed.
///
/// This error maintains a path to the component that is actually errorneous
/// in the nested components.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[allow(clippy::module_name_repetitions)]
pub struct VerifyError {
components: Vec<String>,
reason: String,
}

impl VerifyError {
/// Makes range error from `actual: impl Display` that is out of range.
///
/// # Examples
///
/// ```
/// # use flacenc::error::*;
/// let err = VerifyError::new("order", "must be non-negative");
/// assert_eq!(
/// format!("{}", err),
/// "verification error: `order` is not valid. reason: must be non-negative"
/// );
pub fn new(component: &str, reason: &str) -> Self {
Self {
components: vec![component.to_owned()],
reason: reason.to_owned(),
}
}

/// Prepends the name of an enclosing component to the error location.
///
/// # Examples
///
/// ```
/// # use flacenc::error::*;
/// let err = VerifyError::new("order", "must be non-negative");
/// let err = err.within("encoder");
/// assert_eq!(
/// format!("{}", err),
/// "verification error: `encoder.order` is not valid. reason: must be non-negative"
/// );
/// ```
#[must_use]
pub fn within(self, component: &str) -> Self {
let mut components = self.components;
Expand All @@ -181,6 +212,16 @@ impl VerifyError {
Self { components, reason }
}

/// Gets dot-separated path string for the error location.
///
/// # Examples
///
/// ```
/// # use flacenc::error::*;
/// let err = VerifyError::new("order", "must be non-negative");
/// let err = err.within("encoder");
/// assert_eq!(err.path(), "encoder.order");
/// ```
pub fn path(&self) -> String {
let mut path = String::new();
for (i, name) in self.components.iter().rev().enumerate() {
Expand Down Expand Up @@ -210,6 +251,7 @@ impl fmt::Display for VerifyError {
}
}

/// Trait for verifiable structs.
pub trait Verify {
/// Verifies there's no internal data inconsistency.
///
Expand All @@ -219,6 +261,7 @@ pub trait Verify {
fn verify(&self) -> Result<(), VerifyError>;
}

/// Struct that wraps errors from `Source`.
#[derive(Clone, Debug)]
#[allow(clippy::module_name_repetitions)]
pub struct SourceError {
Expand All @@ -227,26 +270,77 @@ pub struct SourceError {
}

impl SourceError {
/// Constructs `SourceError` by choosing a reason.
///
/// # Examples
///
/// ```
/// # use flacenc::error::*;
/// let err = SourceError::by_reason(SourceErrorReason::Open);
/// assert_eq!(
/// format!("{}", err),
/// "error occured while reading <unknown>. reason: cannot open file."
/// );
/// ```
pub const fn by_reason(reason: SourceErrorReason) -> Self {
Self {
source_name: None,
reason,
}
}

/// Constructs `SourceError` with unknown (hidden) reason.
///
/// # Examples
///
/// ```
/// # use flacenc::error::*;
/// let err = SourceError::by_reason(SourceErrorReason::Open);
/// assert_eq!(
/// format!("{}", err),
/// "error occured while reading <unknown>. reason: cannot open file."
/// );
/// ```
pub const fn from_unknown() -> Self {
Self {
source_name: None,
reason: SourceErrorReason::IO(None),
}
}

/// Constructs `SourceError` from an `io::Error`.
///
/// # Examples
///
/// ```
/// # use flacenc::error::*;
/// # use std::io;
/// let err = SourceError::from_io_error(io::Error::new(io::ErrorKind::Other, "oh no!"));
/// assert_eq!(
/// format!("{}", err),
/// "error occured while reading <unknown>. reason: I/O error: oh no!."
/// );
/// ```
pub fn from_io_error<E: Error + 'static>(e: E) -> Self {
Self {
source_name: None,
reason: SourceErrorReason::IO(Some(Rc::new(e))),
}
}

/// Set path as the source name (informative when `Source` is file-based.)
///
/// # Examples
///
/// ```
/// # use flacenc::error::*;
/// let err = SourceError::by_reason(SourceErrorReason::Open);
/// let err = err.set_path("missing.wav");
/// assert_eq!(
/// format!("{}", err),
/// "error occured while reading missing.wav. reason: cannot open file."
/// );
/// ```
#[must_use]
pub fn set_path<P: AsRef<Path>>(self, path: P) -> Self {
Self {
Expand All @@ -256,12 +350,18 @@ impl SourceError {
}
}

/// Enum covering possible error reasons from `Source`.
#[derive(Clone, Debug)]
pub enum SourceErrorReason {
/// The source file cannot be opened.
Open,
/// `FrameBuf` is not properly prepared.
InvalidBuffer,
/// The content of file is not readable.
InvalidFormat,
/// Type of file is not supported.
UnsupportedFormat,
/// Other IO-related error.
IO(Option<Rc<dyn Error + 'static>>),
}

Expand Down
2 changes: 1 addition & 1 deletion src/par.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ impl ParFrameBuf {
if read_samples == 0 {
break 'feed;
}
numbuf.frame_number = Some(context.current_frame_number());
numbuf.frame_number = context.current_frame_number();
}
if self.encode_queue.0.is_empty() {
worker_starvation_count += 1;
Expand Down
Loading

0 comments on commit a9c16a0

Please sign in to comment.