diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2198872..6c4cfbd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ env: RUST_BACKTRACE: 1 # Pin the nightly toolchain to prevent breakage. # This should be occasionally updated. - RUST_NIGHTLY_TOOLCHAIN: nightly-2023-02-14 + RUST_NIGHTLY_TOOLCHAIN: nightly-2024-05-10 jobs: env: diff --git a/euphony-command/src/api.rs b/euphony-command/src/api.rs index e001537..ae79ea1 100644 --- a/euphony-command/src/api.rs +++ b/euphony-command/src/api.rs @@ -3,62 +3,6 @@ use std::{fs, io, path::Path, time::Duration}; bach::scope::define!(scope, Box); -struct WriterOut(O); - -impl super::Handler for WriterOut { - fn advance_time(&mut self, msg: AdvanceTime) -> io::Result<()> { - msg.encode(&mut self.0) - } - - fn set_timing(&mut self, msg: SetTiming) -> io::Result<()> { - msg.encode(&mut self.0) - } - - fn create_group(&mut self, msg: CreateGroup) -> io::Result<()> { - msg.encode(&mut self.0) - } - - fn spawn_node(&mut self, msg: SpawnNode) -> io::Result<()> { - msg.encode(&mut self.0) - } - - fn fork_node(&mut self, msg: ForkNode) -> io::Result<()> { - msg.encode(&mut self.0) - } - - fn emit_midi(&mut self, msg: EmitMidi) -> io::Result<()> { - msg.encode(&mut self.0) - } - - fn set_parameter(&mut self, msg: SetParameter) -> io::Result<()> { - msg.encode(&mut self.0) - } - - fn pipe_parameter(&mut self, msg: PipeParameter) -> io::Result<()> { - msg.encode(&mut self.0) - } - - fn finish_node(&mut self, msg: FinishNode) -> io::Result<()> { - msg.encode(&mut self.0) - } - - fn init_buffer(&mut self, msg: InitBuffer) -> io::Result<()> { - msg.encode(&mut self.0) - } - - fn load_buffer(&mut self, msg: LoadBuffer) -> io::Result<()> { - msg.encode(&mut self.0) - } - - fn set_buffer(&mut self, msg: SetBuffer) -> io::Result<()> { - msg.encode(&mut self.0) - } - - fn finish(&mut self) -> io::Result<()> { - self.0.flush() - } -} - pub fn set_file(path: &Path) { let file = fs::File::create(path).unwrap(); let file = io::BufWriter::new(file); @@ -70,106 +14,115 @@ pub fn set_stdout() { } pub fn set_writer(out: W) { - let out = WriterOut(out); + let out = handler::Writer(out); let out = Box::new(out); scope::set(Some(out)); } macro_rules! emit { - ($method:ident($msg:expr)) => { - scope::try_borrow_mut_with(|output| { - let msg = $msg; - if let Some(output) = output.as_mut() { - output - .$method(msg) - .expect("failed to emit message to output"); - } else { - println!("{msg}"); - } - }) + ($method:ident(| $($arg:ident : $arg_t:ty),* $(,)? | $msg:expr)) => { + pub fn $method($($arg: $arg_t),*) { + scope::try_borrow_mut_with(|output| { + let msg = $msg; + if let Some(output) = output.as_mut() { + output + .$method(msg) + .expect("failed to emit message to output"); + } else { + println!("{msg}"); + } + }) + } }; } -pub fn advance_time(ticks: u64) { - emit!(advance_time(AdvanceTime { ticks })) -} +emit!(advance_time(|ticks: u64| AdvanceTime { ticks })); -pub fn set_timing(nanos_per_tick: Duration, ticks_per_beat: u64) { - emit!(set_timing(SetTiming { +emit!(set_timing( + |nanos_per_tick: Duration, ticks_per_beat: u64| SetTiming { nanos_per_tick: nanos_per_tick.as_nanos() as _, ticks_per_beat, - })) -} + } +)); -pub fn create_group(id: u64, name: String) { - emit!(create_group(CreateGroup { id, name })) -} +emit!(create_group(|id: u64, name: &str| CreateGroup { + id, + name: name.to_string(), +})); -pub fn spawn_node(id: u64, processor: u64, group: Option) { - emit!(spawn_node(SpawnNode { +emit!(spawn_node(|id: u64, processor: u64, group: Option| { + SpawnNode { id, group, processor, - })) -} - -pub fn fork_node(source: u64, target: u64) { - emit!(fork_node(ForkNode { source, target })) -} - -pub fn emit_midi(data: [u8; 3], group: Option) { - emit!(emit_midi(EmitMidi { data, group })) -} - -pub fn set_parameter(target_node: u64, target_parameter: u64, value: f64) { - emit!(set_parameter(SetParameter { - target_node, - target_parameter, - value: value.to_bits(), - })) -} + } +})); + +emit!(fork_node(|source: u64, target: u64| ForkNode { + source, + target +})); + +emit!(emit_midi(|data: [u8; 3], group: Option| EmitMidi { + data, + group +})); + +emit!(set_parameter( + |target_node: u64, target_parameter: u64, value: f64| { + SetParameter { + target_node, + target_parameter, + value: value.to_bits(), + } + } +)); -pub fn pipe_parameter(target_node: u64, target_parameter: u64, source_node: u64) { - emit!(pipe_parameter(PipeParameter { +emit!(pipe_parameter( + |target_node: u64, target_parameter: u64, source_node: u64| PipeParameter { source_node, target_node, target_parameter, - })) -} + } +)); -pub fn finish_node(id: u64) { - emit!(finish_node(FinishNode { node: id })) -} +emit!(finish_node(|id: u64| FinishNode { node: id })); -pub fn init_buffer(source: &Path, meta: &Path) { +emit!(init_buffer(|source: &Path, meta: &Path| { let source = source.to_string_lossy().to_string(); let meta = meta.to_string_lossy().to_string(); - emit!(init_buffer(InitBuffer { source, meta })) -} + InitBuffer { source, meta } +})); -pub fn load_buffer(id: u64, path: &Path, ext: &str) { +emit!(load_buffer(|id: u64, path: &Path, ext: &str| { let path = path.to_string_lossy().to_string(); let ext = ext.to_string(); - emit!(load_buffer(LoadBuffer { id, path, ext })) -} - -pub fn set_buffer(target_node: u64, target_parameter: u64, buffer: u64, buffer_channel: u64) { - emit!(set_buffer(SetBuffer { - target_node, - target_parameter, - buffer, - buffer_channel, - })) -} + LoadBuffer { id, path, ext } +})); + +emit!(set_buffer( + |target_node: u64, target_parameter: u64, buffer: u64, buffer_channel: u64| { + SetBuffer { + target_node, + target_parameter, + buffer, + buffer_channel, + } + } +)); pub fn flush() { scope::try_borrow_mut_with(|output| { if let Some(output) = output.as_mut() { - output.finish().unwrap(); + output.flush().unwrap(); } }); } pub fn finish() { - flush(); + scope::try_borrow_mut_with(|output| { + if let Some(output) = output.as_mut() { + output.finish().unwrap(); + } + }); } diff --git a/euphony-command/src/codec.rs b/euphony-command/src/codec.rs new file mode 100644 index 0000000..7de9ac5 --- /dev/null +++ b/euphony-command/src/codec.rs @@ -0,0 +1,177 @@ +use super::*; + +pub fn decode(input: &mut R, handler: &mut H) -> io::Result<()> { + while decode_one(input, handler)?.is_continue() {} + Ok(()) +} + +#[deny(unreachable_patterns)] +pub fn decode_one( + input: &mut R, + handler: &mut H, +) -> io::Result> { + let tag = match input.read_u8() { + Ok(tag) => tag, + Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => { + return Ok(ControlFlow::Break(())); + } + Err(err) => return Err(err), + }; + + match tag { + AdvanceTime::TAG => { + let msg = AdvanceTime::decode(tag, input)?; + handler.advance_time(msg)?; + } + SetTiming::TAG => { + let msg = SetTiming::decode(tag, input)?; + handler.set_timing(msg)?; + } + CreateGroup::TAG => { + let msg = CreateGroup::decode(tag, input)?; + handler.create_group(msg)?; + } + SpawnNode::TAG_NO_GROUP | SpawnNode::TAG_WITH_GROUP => { + let msg = SpawnNode::decode(tag, input)?; + handler.spawn_node(msg)?; + } + ForkNode::TAG => { + let msg = ForkNode::decode(tag, input)?; + handler.fork_node(msg)?; + } + EmitMidi::TAG_NO_GROUP | EmitMidi::TAG_WITH_GROUP => { + let msg = EmitMidi::decode(tag, input)?; + handler.emit_midi(msg)?; + } + SetParameter::TAG_PARAM | SetParameter::TAG_NONE => { + let msg = SetParameter::decode(tag, input)?; + handler.set_parameter(msg)?; + } + PipeParameter::TAG_PARAM | PipeParameter::TAG_NONE => { + let msg = PipeParameter::decode(tag, input)?; + handler.pipe_parameter(msg)?; + } + FinishNode::TAG => { + let msg = FinishNode::decode(tag, input)?; + handler.finish_node(msg)?; + } + InitBuffer::TAG => { + let msg = InitBuffer::decode(tag, input)?; + handler.init_buffer(msg)?; + } + LoadBuffer::TAG => { + let msg = LoadBuffer::decode(tag, input)?; + handler.load_buffer(msg)?; + } + SetBuffer::TAG => { + let msg = SetBuffer::decode(tag, input)?; + handler.set_buffer(msg)?; + } + _ => { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + format!("invalid tag: 0x{tag:x}"), + )) + } + } + + Ok(ControlFlow::Continue(())) +} + +pub trait Codec: Sized { + fn encode(&self, output: &mut W) -> io::Result<()>; + fn decode(tag: u8, input: &mut R) -> io::Result; +} + +pub trait WriteExt { + fn write_u8(&mut self, value: u8) -> io::Result<()>; + #[allow(dead_code)] + fn write_u16(&mut self, value: u16) -> io::Result<()>; + fn write_u32(&mut self, value: u32) -> io::Result<()>; + fn write_u64(&mut self, value: u64) -> io::Result<()>; +} + +impl WriteExt for W { + #[inline] + fn write_u8(&mut self, value: u8) -> io::Result<()> { + self.write_all(&[value])?; + Ok(()) + } + + #[inline] + fn write_u16(&mut self, value: u16) -> io::Result<()> { + self.write_all(&value.to_le_bytes())?; + Ok(()) + } + + #[inline] + fn write_u32(&mut self, value: u32) -> io::Result<()> { + self.write_all(&value.to_le_bytes())?; + Ok(()) + } + + #[inline] + fn write_u64(&mut self, value: u64) -> io::Result<()> { + self.write_all(&value.to_le_bytes())?; + Ok(()) + } +} + +pub trait ReadExt { + fn read_u8(&mut self) -> io::Result; + #[allow(dead_code)] + fn read_u16(&mut self) -> io::Result; + fn read_u32(&mut self) -> io::Result; + fn read_u64(&mut self) -> io::Result; + fn read_string(&mut self, len: usize) -> io::Result; +} + +impl ReadExt for R { + #[inline] + fn read_u8(&mut self) -> io::Result { + let mut value = [0u8; 1]; + self.read_exact(&mut value)?; + Ok(value[0]) + } + + #[inline] + fn read_u16(&mut self) -> io::Result { + let mut value = [0u8; 2]; + self.read_exact(&mut value)?; + let value = u16::from_le_bytes(value); + Ok(value) + } + + #[inline] + fn read_u32(&mut self) -> io::Result { + let mut value = [0u8; 4]; + self.read_exact(&mut value)?; + let value = u32::from_le_bytes(value); + Ok(value) + } + + #[inline] + fn read_u64(&mut self) -> io::Result { + let mut value = [0u8; 8]; + self.read_exact(&mut value)?; + let value = u64::from_le_bytes(value); + Ok(value) + } + + #[inline] + fn read_string(&mut self, len: usize) -> io::Result { + Ok(if len > 0 { + let mut name = vec![0; len]; + self.read_exact(&mut name)?; + match String::from_utf8_lossy(&name) { + std::borrow::Cow::Owned(v) => v, + std::borrow::Cow::Borrowed(_) => unsafe { + // the lossy will check that this is valid + String::from_utf8_unchecked(name) + }, + } + } else { + String::new() + }) + } +} diff --git a/euphony-command/src/handler.rs b/euphony-command/src/handler.rs new file mode 100644 index 0000000..59297d4 --- /dev/null +++ b/euphony-command/src/handler.rs @@ -0,0 +1,139 @@ +use super::*; +use std::io; + +pub trait Handler { + fn advance_time(&mut self, msg: AdvanceTime) -> io::Result<()>; + fn set_timing(&mut self, msg: SetTiming) -> io::Result<()>; + fn create_group(&mut self, msg: CreateGroup) -> io::Result<()>; + fn spawn_node(&mut self, msg: SpawnNode) -> io::Result<()>; + fn fork_node(&mut self, msg: ForkNode) -> io::Result<()>; + fn emit_midi(&mut self, msg: EmitMidi) -> io::Result<()>; + fn set_parameter(&mut self, msg: SetParameter) -> io::Result<()>; + fn pipe_parameter(&mut self, msg: PipeParameter) -> io::Result<()>; + fn finish_node(&mut self, msg: FinishNode) -> io::Result<()>; + fn init_buffer(&mut self, msg: InitBuffer) -> io::Result<()>; + fn load_buffer(&mut self, msg: LoadBuffer) -> io::Result<()>; + fn set_buffer(&mut self, msg: SetBuffer) -> io::Result<()>; + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + fn finish(&mut self) -> io::Result<()> { + Ok(()) + } +} + +fn push_msg(output: &mut String, v: T) -> io::Result<()> { + use std::fmt::Write; + let _ = writeln!(output, "{v}"); + Ok(()) +} + +impl Handler for String { + fn advance_time(&mut self, msg: AdvanceTime) -> io::Result<()> { + push_msg(self, msg) + } + + fn set_timing(&mut self, msg: SetTiming) -> io::Result<()> { + push_msg(self, msg) + } + + fn create_group(&mut self, msg: CreateGroup) -> io::Result<()> { + push_msg(self, msg) + } + + fn spawn_node(&mut self, msg: SpawnNode) -> io::Result<()> { + push_msg(self, msg) + } + + fn fork_node(&mut self, msg: ForkNode) -> io::Result<()> { + push_msg(self, msg) + } + + fn emit_midi(&mut self, msg: EmitMidi) -> io::Result<()> { + push_msg(self, msg) + } + + fn set_parameter(&mut self, msg: SetParameter) -> io::Result<()> { + push_msg(self, msg) + } + + fn pipe_parameter(&mut self, msg: PipeParameter) -> io::Result<()> { + push_msg(self, msg) + } + + fn finish_node(&mut self, msg: FinishNode) -> io::Result<()> { + push_msg(self, msg) + } + + fn init_buffer(&mut self, msg: InitBuffer) -> io::Result<()> { + push_msg(self, msg) + } + + fn load_buffer(&mut self, msg: LoadBuffer) -> io::Result<()> { + push_msg(self, msg) + } + + fn set_buffer(&mut self, msg: SetBuffer) -> io::Result<()> { + push_msg(self, msg) + } +} + +pub struct Writer(pub O); + +impl super::Handler for Writer { + fn advance_time(&mut self, msg: AdvanceTime) -> io::Result<()> { + msg.encode(&mut self.0) + } + + fn set_timing(&mut self, msg: SetTiming) -> io::Result<()> { + msg.encode(&mut self.0) + } + + fn create_group(&mut self, msg: CreateGroup) -> io::Result<()> { + msg.encode(&mut self.0) + } + + fn spawn_node(&mut self, msg: SpawnNode) -> io::Result<()> { + msg.encode(&mut self.0) + } + + fn fork_node(&mut self, msg: ForkNode) -> io::Result<()> { + msg.encode(&mut self.0) + } + + fn emit_midi(&mut self, msg: EmitMidi) -> io::Result<()> { + msg.encode(&mut self.0) + } + + fn set_parameter(&mut self, msg: SetParameter) -> io::Result<()> { + msg.encode(&mut self.0) + } + + fn pipe_parameter(&mut self, msg: PipeParameter) -> io::Result<()> { + msg.encode(&mut self.0) + } + + fn finish_node(&mut self, msg: FinishNode) -> io::Result<()> { + msg.encode(&mut self.0) + } + + fn init_buffer(&mut self, msg: InitBuffer) -> io::Result<()> { + msg.encode(&mut self.0) + } + + fn load_buffer(&mut self, msg: LoadBuffer) -> io::Result<()> { + msg.encode(&mut self.0) + } + + fn set_buffer(&mut self, msg: SetBuffer) -> io::Result<()> { + msg.encode(&mut self.0) + } + + fn flush(&mut self) -> io::Result<()> { + self.0.flush() + } + + fn finish(&mut self) -> io::Result<()> { + self.0.flush() + } +} diff --git a/euphony-command/src/lib.rs b/euphony-command/src/lib.rs index 1a9dabc..6b8b653 100644 --- a/euphony-command/src/lib.rs +++ b/euphony-command/src/lib.rs @@ -2,259 +2,16 @@ use core::{fmt, ops::ControlFlow}; use std::io; pub mod api; +mod codec; +mod handler; -#[cfg(test)] -use bolero::generator::*; +pub use codec::{decode, decode_one, Codec}; +pub use handler::Handler; -pub trait Handler { - fn advance_time(&mut self, msg: AdvanceTime) -> io::Result<()>; - fn set_timing(&mut self, msg: SetTiming) -> io::Result<()>; - fn create_group(&mut self, msg: CreateGroup) -> io::Result<()>; - fn spawn_node(&mut self, msg: SpawnNode) -> io::Result<()>; - fn fork_node(&mut self, msg: ForkNode) -> io::Result<()>; - fn emit_midi(&mut self, msg: EmitMidi) -> io::Result<()>; - fn set_parameter(&mut self, msg: SetParameter) -> io::Result<()>; - fn pipe_parameter(&mut self, msg: PipeParameter) -> io::Result<()>; - fn finish_node(&mut self, msg: FinishNode) -> io::Result<()>; - fn init_buffer(&mut self, msg: InitBuffer) -> io::Result<()>; - fn load_buffer(&mut self, msg: LoadBuffer) -> io::Result<()>; - fn set_buffer(&mut self, msg: SetBuffer) -> io::Result<()>; - fn finish(&mut self) -> io::Result<()> { - Ok(()) - } -} - -fn push_msg(output: &mut String, v: T) -> io::Result<()> { - use std::fmt::Write; - let _ = writeln!(output, "{v}"); - Ok(()) -} - -impl Handler for String { - fn advance_time(&mut self, msg: AdvanceTime) -> io::Result<()> { - push_msg(self, msg) - } - - fn set_timing(&mut self, msg: SetTiming) -> io::Result<()> { - push_msg(self, msg) - } - - fn create_group(&mut self, msg: CreateGroup) -> io::Result<()> { - push_msg(self, msg) - } - - fn spawn_node(&mut self, msg: SpawnNode) -> io::Result<()> { - push_msg(self, msg) - } - - fn fork_node(&mut self, msg: ForkNode) -> io::Result<()> { - push_msg(self, msg) - } - - fn emit_midi(&mut self, msg: EmitMidi) -> io::Result<()> { - push_msg(self, msg) - } - - fn set_parameter(&mut self, msg: SetParameter) -> io::Result<()> { - push_msg(self, msg) - } - - fn pipe_parameter(&mut self, msg: PipeParameter) -> io::Result<()> { - push_msg(self, msg) - } - - fn finish_node(&mut self, msg: FinishNode) -> io::Result<()> { - push_msg(self, msg) - } +use codec::{ReadExt, WriteExt}; - fn init_buffer(&mut self, msg: InitBuffer) -> io::Result<()> { - push_msg(self, msg) - } - - fn load_buffer(&mut self, msg: LoadBuffer) -> io::Result<()> { - push_msg(self, msg) - } - - fn set_buffer(&mut self, msg: SetBuffer) -> io::Result<()> { - push_msg(self, msg) - } -} - -pub fn decode(input: &mut R, handler: &mut H) -> io::Result<()> { - while decode_one(input, handler)?.is_continue() {} - Ok(()) -} - -#[deny(unreachable_patterns)] -pub fn decode_one( - input: &mut R, - handler: &mut H, -) -> io::Result> { - let tag = match input.read_u8() { - Ok(tag) => tag, - Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => { - return Ok(ControlFlow::Break(())); - } - Err(err) => return Err(err), - }; - - match tag { - AdvanceTime::TAG => { - let msg = AdvanceTime::decode(tag, input)?; - handler.advance_time(msg)?; - } - SetTiming::TAG => { - let msg = SetTiming::decode(tag, input)?; - handler.set_timing(msg)?; - } - CreateGroup::TAG => { - let msg = CreateGroup::decode(tag, input)?; - handler.create_group(msg)?; - } - SpawnNode::TAG_NO_GROUP | SpawnNode::TAG_WITH_GROUP => { - let msg = SpawnNode::decode(tag, input)?; - handler.spawn_node(msg)?; - } - ForkNode::TAG => { - let msg = ForkNode::decode(tag, input)?; - handler.fork_node(msg)?; - } - EmitMidi::TAG_NO_GROUP | EmitMidi::TAG_WITH_GROUP => { - let msg = EmitMidi::decode(tag, input)?; - handler.emit_midi(msg)?; - } - SetParameter::TAG_PARAM | SetParameter::TAG_NONE => { - let msg = SetParameter::decode(tag, input)?; - handler.set_parameter(msg)?; - } - PipeParameter::TAG_PARAM | PipeParameter::TAG_NONE => { - let msg = PipeParameter::decode(tag, input)?; - handler.pipe_parameter(msg)?; - } - FinishNode::TAG => { - let msg = FinishNode::decode(tag, input)?; - handler.finish_node(msg)?; - } - InitBuffer::TAG => { - let msg = InitBuffer::decode(tag, input)?; - handler.init_buffer(msg)?; - } - LoadBuffer::TAG => { - let msg = LoadBuffer::decode(tag, input)?; - handler.load_buffer(msg)?; - } - SetBuffer::TAG => { - let msg = SetBuffer::decode(tag, input)?; - handler.set_buffer(msg)?; - } - _ => { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - format!("invalid tag: 0x{tag:x}"), - )) - } - } - - Ok(ControlFlow::Continue(())) -} - -pub trait Codec: Sized { - fn encode(&self, output: &mut W) -> io::Result<()>; - fn decode(tag: u8, input: &mut R) -> io::Result; -} - -trait WriteExt { - fn write_u8(&mut self, value: u8) -> io::Result<()>; - #[allow(dead_code)] - fn write_u16(&mut self, value: u16) -> io::Result<()>; - fn write_u32(&mut self, value: u32) -> io::Result<()>; - fn write_u64(&mut self, value: u64) -> io::Result<()>; -} - -impl WriteExt for W { - #[inline] - fn write_u8(&mut self, value: u8) -> io::Result<()> { - self.write_all(&[value])?; - Ok(()) - } - - #[inline] - fn write_u16(&mut self, value: u16) -> io::Result<()> { - self.write_all(&value.to_le_bytes())?; - Ok(()) - } - - #[inline] - fn write_u32(&mut self, value: u32) -> io::Result<()> { - self.write_all(&value.to_le_bytes())?; - Ok(()) - } - - #[inline] - fn write_u64(&mut self, value: u64) -> io::Result<()> { - self.write_all(&value.to_le_bytes())?; - Ok(()) - } -} - -trait ReadExt { - fn read_u8(&mut self) -> io::Result; - #[allow(dead_code)] - fn read_u16(&mut self) -> io::Result; - fn read_u32(&mut self) -> io::Result; - fn read_u64(&mut self) -> io::Result; - fn read_string(&mut self, len: usize) -> io::Result; -} - -impl ReadExt for R { - #[inline] - fn read_u8(&mut self) -> io::Result { - let mut value = [0u8; 1]; - self.read_exact(&mut value)?; - Ok(value[0]) - } - - #[inline] - fn read_u16(&mut self) -> io::Result { - let mut value = [0u8; 2]; - self.read_exact(&mut value)?; - let value = u16::from_le_bytes(value); - Ok(value) - } - - #[inline] - fn read_u32(&mut self) -> io::Result { - let mut value = [0u8; 4]; - self.read_exact(&mut value)?; - let value = u32::from_le_bytes(value); - Ok(value) - } - - #[inline] - fn read_u64(&mut self) -> io::Result { - let mut value = [0u8; 8]; - self.read_exact(&mut value)?; - let value = u64::from_le_bytes(value); - Ok(value) - } - - #[inline] - fn read_string(&mut self, len: usize) -> io::Result { - Ok(if len > 0 { - let mut name = vec![0; len]; - self.read_exact(&mut name)?; - match String::from_utf8_lossy(&name) { - std::borrow::Cow::Owned(v) => v, - std::borrow::Cow::Borrowed(_) => unsafe { - // the lossy will check that this is valid - String::from_utf8_unchecked(name) - }, - } - } else { - String::new() - }) - } -} +#[cfg(test)] +use bolero::generator::*; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(test, derive(TypeGenerator))] diff --git a/euphony-units/src/ratio/mod.rs b/euphony-units/src/ratio/mod.rs index 5f7b316..c0b0d51 100644 --- a/euphony-units/src/ratio/mod.rs +++ b/euphony-units/src/ratio/mod.rs @@ -42,7 +42,7 @@ impl PartialEq for Ratio { impl PartialOrd for Ratio { fn partial_cmp(&self, other: &Self) -> Option { - self.as_ratio().partial_cmp(&other.as_ratio()) + Some(self.cmp(other)) } } diff --git a/euphony/src/group.rs b/euphony/src/group.rs index 6b12047..1027aac 100644 --- a/euphony/src/group.rs +++ b/euphony/src/group.rs @@ -34,7 +34,7 @@ impl Group { let id = groups.len() as u64; - crate::output::create_group(id, name.to_string()); + crate::output::create_group(id, name); groups.insert(name.to_owned(), id);