From 0a6e237049ec28772a25c1a79dd487a7fe352c82 Mon Sep 17 00:00:00 2001 From: zawz Date: Mon, 30 Dec 2024 16:10:30 +0100 Subject: [PATCH] chore: apply format --- examples/vmpk.yml | 26 +-- src/cli.rs | 1 - src/config/device.rs | 50 +++-- src/config/event.rs | 27 ++- src/config/mod.rs | 4 +- src/config/run.rs | 28 ++- src/config/serializer/device.rs | 9 +- src/config/serializer/event.rs | 4 +- src/config/serializer/eventenv.rs | 7 +- src/config/serializer/mod.rs | 8 +- src/config/serializer/run.rs | 6 +- src/constant.rs | 3 +- src/error.rs | 4 +- src/event.rs | 153 +++++++++------- src/eventmap.rs | 40 ++-- src/main.rs | 33 ++-- src/midi/backend/alsa.rs | 292 ++++++++++++++++++------------ src/midi/builder.rs | 14 +- src/midi/driver.rs | 2 +- src/midi/input.rs | 137 +++++++++----- src/midi/mod.rs | 12 +- src/midi/port.rs | 10 +- src/midi/portfilter.rs | 12 +- src/run.rs | 93 ++++++---- src/util/mod.rs | 20 +- src/util/range.rs | 52 +++--- src/util/remap.rs | 66 ++++--- src/util/smartset.rs | 102 ++++++----- 28 files changed, 705 insertions(+), 510 deletions(-) diff --git a/examples/vmpk.yml b/examples/vmpk.yml index 99bdb64..547ab4a 100644 --- a/examples/vmpk.yml +++ b/examples/vmpk.yml @@ -1,13 +1,13 @@ log_devices: true devices: - - name: 'VMPK' + - name: "VMPK" max_connections: 1 queue_length: 3 interval: 100ms - connect: - - args: [ "sh", "-c", "echo Hello world!" ] - disconnect: - - args: [ "sh", "-c", "echo Bye!" ] + connect: + - args: ["sh", "-c", "echo Hello world!"] + disconnect: + - args: ["sh", "-c", "echo Bye!"] events: - type: ProgramChange run: @@ -38,28 +38,28 @@ devices: - cmd: "echo [$channel] PitchBend $value $raw $toto" envconf: timestamp: toto - - name: 'VMPK' + - name: "VMPK" log_events: true max_connections: 1 - connect: - - args: [ "sh", "-c", "echo Hello world! 2" ] - disconnect: - - args: [ "sh", "-c", "echo Bye! 2" ] + connect: + - args: ["sh", "-c", "echo Hello world! 2"] + disconnect: + - args: ["sh", "-c", "echo Bye! 2"] events: - type: NoteOff id: 25-30 run: - - args: [ "sh", "-c", "echo 2 [$channel] NoteOff $id" ] + - args: ["sh", "-c", "echo 2 [$channel] NoteOff $id"] - type: NoteOn channel: 0 remap: -1 run: - - args: [ "sh", "-c", "echo 2 [$channel] NoteOn $id $value" ] + - args: ["sh", "-c", "echo 2 [$channel] NoteOn $id $value"] - type: PitchBend remap: 0-100 float: true value: 0-65535 run: - - args: [ "sh", "-c", "echo [$channel] PitchBend $value $raw $toto" ] + - args: ["sh", "-c", "echo [$channel] PitchBend $value $raw $toto"] envconf: timestamp: toto diff --git a/src/cli.rs b/src/cli.rs index 9cefa8c..28c5f95 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -11,4 +11,3 @@ pub struct Cli { #[clap(long, short, action)] pub list: bool, } - diff --git a/src/config/device.rs b/src/config/device.rs index 1cc9022..d165e04 100644 --- a/src/config/device.rs +++ b/src/config/device.rs @@ -1,12 +1,12 @@ use std::time::Duration; +use super::serializer::DeviceConfigSerializer; +use super::{EventConfig, RunConfig}; use crate::event::Event; use crate::util; use crate::Error; -use super::{RunConfig,EventConfig}; -use super::serializer::DeviceConfigSerializer; -#[derive(Debug,Clone)] +#[derive(Debug, Clone)] pub enum Identifier { All, Name(String), @@ -14,7 +14,7 @@ pub enum Identifier { Addr(String), } -#[derive(Debug,Clone)] +#[derive(Debug, Clone)] pub struct DeviceConfig { pub identifier: Identifier, pub max_connections: Option, @@ -29,12 +29,16 @@ pub struct DeviceConfig { impl DeviceConfig { fn run_internal<'a, T>(&self, v: Option) -> Result, Error> where - T: IntoIterator + T: IntoIterator, { let mut r = Vec::new(); if let Some(ev) = v { for e in ev { - if let Some(v) = e.run(Event::new().make_env(None, false)?.to_map(e.envconf.as_ref()))? { + if let Some(v) = e.run( + Event::new() + .make_env(None, false)? + .to_map(e.envconf.as_ref()), + )? { r.push(v); } } @@ -46,7 +50,7 @@ impl DeviceConfig { self.run_internal(self.connect.as_ref()) } - pub fn run_disconnect(&self) -> Result, Error> { + pub fn run_disconnect(&self) -> Result, Error> { self.run_internal(self.disconnect.as_ref()) } } @@ -57,21 +61,33 @@ impl TryFrom for DeviceConfig { Ok(DeviceConfig { identifier: { match (v.name, v.regex, v.addr) { - (Some(_), Some(_), _ ) => return Err(Error::IncompatibleArgs("name","regex")), - (Some(_), None , Some(_)) => return Err(Error::IncompatibleArgs("name","addr")), - (None , Some(_), Some(_)) => return Err(Error::IncompatibleArgs("regex","addr")), - (Some(n), None, None ) => Identifier::Name(n), - (None, Some(r), None ) => Identifier::Regex(regex::Regex::new(&r)?), - (None, None , Some(a)) => Identifier::Addr(a), - (None, None, None ) => Identifier::All, + (Some(_), Some(_), Some(_)) => { + return Err(Error::IncompatibleArgs("name", "regex")) + } + (Some(_), Some(_), None) => { + return Err(Error::IncompatibleArgs("name", "regex")) + } + (Some(_), None, Some(_)) => { + return Err(Error::IncompatibleArgs("name", "addr")) + } + (None, Some(_), Some(_)) => { + return Err(Error::IncompatibleArgs("regex", "addr")) + } + (Some(n), None, None) => Identifier::Name(n), + (None, Some(r), None) => Identifier::Regex(regex::Regex::new(&r)?), + (None, None, Some(a)) => Identifier::Addr(a), + (None, None, None) => Identifier::All, } }, max_connections: v.max_connections, - connect: util::map_opt_tryfrom(v.connect)?, + connect: util::map_opt_tryfrom(v.connect)?, disconnect: util::map_opt_tryfrom(v.disconnect)?, - events: util::map_opt_tryfrom(v.events)?, + events: util::map_opt_tryfrom(v.events)?, queue_length: v.queue_length.unwrap_or(256), - interval: v.interval.map(|x| x.unwrap()).unwrap_or_else(|| Duration::new(0, 0)), + interval: v + .interval + .map(|x| x.unwrap()) + .unwrap_or_else(|| Duration::new(0, 0)), log: v.log_events.unwrap_or(false), }) } diff --git a/src/config/event.rs b/src/config/event.rs index e435562..0e8c93f 100644 --- a/src/config/event.rs +++ b/src/config/event.rs @@ -1,6 +1,6 @@ use super::RunConfig; -use crate::event::{Event,EventType}; -use crate::util::{self, SmartSet, Range, Remapper}; +use crate::event::{Event, EventType}; +use crate::util::{self, Range, Remapper, SmartSet}; use super::serializer::EventConfigSerializer; @@ -32,7 +32,7 @@ lazy_static! { }; } -#[derive(Debug,Clone)] +#[derive(Debug, Clone)] pub struct EventConfig { pub run: Vec, pub r#type: EventType, @@ -46,7 +46,7 @@ pub struct EventConfig { impl EventConfig { pub fn match_value(&self, event: &Event) -> bool { match &self.value { - Some(v) => v.set.contains(&event.value), + Some(v) => v.set.contains(&event.value), None => true, } } @@ -59,21 +59,30 @@ impl TryFrom for EventConfig { run: util::map_tryfrom(v.run)?, r#type: v.r#type, channel: match v.r#type.has_channel() { - true => v.channel.unwrap_or_else(|| CHANNEL_DEFAULT_MAP.clone()), + true => v.channel.unwrap_or_else(|| CHANNEL_DEFAULT_MAP.clone()), false => NULL_DEFAULT_MAP.clone(), }, id: match v.r#type.has_id() { - true => v.id.unwrap_or_else(|| ID_DEFAULT_MAP.clone()), + true => v.id.unwrap_or_else(|| ID_DEFAULT_MAP.clone()), false => NULL_DEFAULT_MAP.clone(), }, - remap: v.remap.map(|x| Remapper::new(Range::new(v.r#type.min_value() as f64, v.r#type.max_value() as f64), x )), + remap: v.remap.map(|x| { + Remapper::new( + Range::new(v.r#type.min_value() as f64, v.r#type.max_value() as f64), + x, + ) + }), float: v.float.unwrap_or(false), value: v.value, }; if let Some(remap) = &r.remap { let range = remap.src(); - if range.start() < i64::MIN as f64 { return Err(Self::Error::RemapTooLow(range.start())) } - if range.end() > i64::MAX as f64 { return Err(Self::Error::RemapTooBig(range.end())) } + if range.start() < i64::MIN as f64 { + return Err(Self::Error::RemapTooLow(range.start())); + } + if range.end() > i64::MAX as f64 { + return Err(Self::Error::RemapTooBig(range.end())); + } } Ok(r) } diff --git a/src/config/mod.rs b/src/config/mod.rs index 9c38975..5b7d9dd 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,5 +1,5 @@ -pub mod event; pub mod device; +pub mod event; pub mod run; pub mod serializer; @@ -14,7 +14,7 @@ pub use event::EventConfig; pub use run::RunConfig; pub type EventEnvMap = serializer::EventEnvSerializer; -#[derive(Clone,Debug)] +#[derive(Clone, Debug)] pub struct Config { pub log: bool, pub driver: Option, diff --git a/src/config/run.rs b/src/config/run.rs index 104fdd6..61c9a4e 100644 --- a/src/config/run.rs +++ b/src/config/run.rs @@ -4,7 +4,7 @@ use std::process::{Command, ExitStatus}; use super::serializer::RunConfigSerializer; use super::EventEnvMap; -#[derive(Debug,Clone)] +#[derive(Debug, Clone)] pub struct RunConfig { pub args: Vec, pub envconf: Option, @@ -19,9 +19,7 @@ impl RunConfig { } c.envs(env); if self.detach { - std::thread::spawn(move || { - c.status() - }); + std::thread::spawn(move || c.status()); Ok(None) } else { c.status().map(|v| Some(v)) @@ -34,19 +32,17 @@ impl TryFrom for RunConfig { fn try_from(v: RunConfigSerializer) -> Result { let args = if v.args.is_some() { v.args.unwrap() - } - else if v.cmd.is_some() { + } else if v.cmd.is_some() { crate::run::cross_shell(v.cmd.as_ref().unwrap()) - } - else { - return Err(crate::Error::from(crate::error::ConfigError::RunMissingArgs)); + } else { + return Err(crate::Error::from( + crate::error::ConfigError::RunMissingArgs, + )); }; - Ok( - RunConfig { - args, - envconf: v.envconf, - detach: v.detach.unwrap_or(false), - } - ) + Ok(RunConfig { + args, + envconf: v.envconf, + detach: v.detach.unwrap_or(false), + }) } } diff --git a/src/config/serializer/device.rs b/src/config/serializer/device.rs index 0622617..dcb362b 100644 --- a/src/config/serializer/device.rs +++ b/src/config/serializer/device.rs @@ -1,11 +1,11 @@ use std::time::Duration; -use super::{RunConfigSerializer,EventConfigSerializer}; +use super::{EventConfigSerializer, RunConfigSerializer}; use duration_str::deserialize_duration; use serde::Deserialize; -#[derive(Debug,Clone,Deserialize)] +#[derive(Debug, Clone, Deserialize)] #[serde(untagged)] pub enum DurationWrapper { #[serde(deserialize_with = "deserialize_duration")] @@ -13,15 +13,14 @@ pub enum DurationWrapper { } impl DurationWrapper { - pub fn unwrap(self) -> Duration - { + pub fn unwrap(self) -> Duration { match self { DurationWrapper::Some(v) => v, } } } -#[derive(Deserialize,Debug,Clone)] +#[derive(Deserialize, Debug, Clone)] #[serde(deny_unknown_fields)] pub struct DeviceConfigSerializer { pub name: Option, diff --git a/src/config/serializer/event.rs b/src/config/serializer/event.rs index a5dfd5a..f0ee9c4 100644 --- a/src/config/serializer/event.rs +++ b/src/config/serializer/event.rs @@ -1,10 +1,10 @@ use super::RunConfigSerializer; use crate::event::EventType; -use crate::util::{SmartSet,Range}; +use crate::util::{Range, SmartSet}; use serde::Deserialize; -#[derive(Deserialize,Debug,Clone)] +#[derive(Deserialize, Debug, Clone)] #[serde(deny_unknown_fields)] pub struct EventConfigSerializer { pub run: Vec, diff --git a/src/config/serializer/eventenv.rs b/src/config/serializer/eventenv.rs index 757e331..112616b 100644 --- a/src/config/serializer/eventenv.rs +++ b/src/config/serializer/eventenv.rs @@ -1,7 +1,6 @@ +use serde::{Deserialize, Serialize}; -use serde::{Serialize,Deserialize}; - -#[derive(Serialize,Deserialize,Debug,Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(deny_unknown_fields)] pub struct EventEnvSerializer { pub channel: Option, @@ -10,4 +9,4 @@ pub struct EventEnvSerializer { pub rawvalue: Option, pub timestamp: Option, pub value: Option, -} \ No newline at end of file +} diff --git a/src/config/serializer/mod.rs b/src/config/serializer/mod.rs index 7b97a25..df57036 100644 --- a/src/config/serializer/mod.rs +++ b/src/config/serializer/mod.rs @@ -1,16 +1,16 @@ -pub mod event; pub mod device; -pub mod run; +pub mod event; pub mod eventenv; +pub mod run; pub use device::DeviceConfigSerializer; pub use event::EventConfigSerializer; -pub use run::RunConfigSerializer; pub use eventenv::EventEnvSerializer; +pub use run::RunConfigSerializer; use serde::Deserialize; -#[derive(Deserialize,Clone,Debug)] +#[derive(Deserialize, Clone, Debug)] #[serde(deny_unknown_fields)] pub struct ConfigSerializer { pub log_devices: Option, diff --git a/src/config/serializer/run.rs b/src/config/serializer/run.rs index 87556e0..edea09f 100644 --- a/src/config/serializer/run.rs +++ b/src/config/serializer/run.rs @@ -1,12 +1,12 @@ use super::EventEnvSerializer; -use serde::{Serialize,Deserialize}; +use serde::{Deserialize, Serialize}; -#[derive(Serialize,Deserialize,Debug,Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(deny_unknown_fields)] pub struct RunConfigSerializer { pub args: Option>, - pub cmd: Option, + pub cmd: Option, pub envconf: Option, pub detach: Option, } diff --git a/src/constant.rs b/src/constant.rs index 7a6f8a3..fe16d6e 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -1,4 +1,3 @@ - pub const CLIENT_NAME: &str = "rmidimap"; pub const CLIENT_NAME_HANDLER: &str = "rmidimap-handler"; -pub const CLIENT_NAME_EVENT: &str = "rmidimap-event-watcher"; \ No newline at end of file +pub const CLIENT_NAME_EVENT: &str = "rmidimap-event-watcher"; diff --git a/src/error.rs b/src/error.rs index c9706e7..37c95fc 100644 --- a/src/error.rs +++ b/src/error.rs @@ -8,7 +8,7 @@ use crate::midi::backend::alsa::AlsaError; use thiserror::Error; -#[derive(Error,Debug)] +#[derive(Error, Debug)] pub enum Error { #[error(transparent)] IO(#[from] std::io::Error), @@ -44,7 +44,7 @@ pub enum Error { Unknown, } -#[derive(Error,Debug)] +#[derive(Error, Debug)] pub enum ConfigError { #[error("run config is missing execution configuration, either \"args\" or \"cmd\" has to be specified")] RunMissingArgs, diff --git a/src/event.rs b/src/event.rs index f745f5c..67f35c5 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,11 +1,11 @@ +use std::fmt::{Display, Write}; use std::{collections::HashMap, time::SystemTime}; -use std::fmt::{Write,Display}; use crate::config::EventEnvMap; use crate::util::Remapper; use crate::Error; -use serde::{Serialize,Deserialize}; +use serde::{Deserialize, Serialize}; use lazy_static::lazy_static; @@ -21,11 +21,12 @@ lazy_static! { } pub fn event_to_key(r#type: EventType, channel: u8, id: u8) -> u32 { - (r#type as u32)*256*256 + (channel as u32)*256 + (id as u32) + (r#type as u32) * 256 * 256 + (channel as u32) * 256 + (id as u32) } +#[rustfmt::skip] #[repr(u8)] -#[derive(Serialize,Deserialize,Debug,Copy,Clone,Default,Display)] +#[derive(Serialize, Deserialize, Debug, Copy, Clone, Default, enum_display_derive::Display)] pub enum EventType { #[default] Unknown = 0b0000, @@ -41,42 +42,36 @@ pub enum EventType { impl EventType { pub fn has_id(&self) -> bool { - !matches!(self, EventType::Unknown | EventType::ChannelPressure | EventType::PitchBend | EventType::System ) + !matches!( + self, + EventType::Unknown + | EventType::ChannelPressure + | EventType::PitchBend + | EventType::System + ) } pub fn has_channel(&self) -> bool { - !matches!(self, EventType::Unknown | EventType::System ) + !matches!(self, EventType::Unknown | EventType::System) } pub fn min_value(&self) -> i32 { match self { - EventType::NoteOff | - EventType::NoteOn | - EventType::Controller - => 0, - EventType::PolyphonicKeyPressure | - EventType::ChannelPressure - => 127, - EventType::PitchBend - => 0, + EventType::NoteOff | EventType::NoteOn | EventType::Controller => 0, + EventType::PolyphonicKeyPressure | EventType::ChannelPressure => 127, + EventType::PitchBend => 0, _ => 0, } } pub fn max_value(&self) -> i32 { match self { - EventType::NoteOff | - EventType::NoteOn | - EventType::Controller - => 127, - EventType::PolyphonicKeyPressure | - EventType::ChannelPressure - => 127, - EventType::PitchBend - => 32767, + EventType::NoteOff | EventType::NoteOn | EventType::Controller => 127, + EventType::PolyphonicKeyPressure | EventType::ChannelPressure => 127, + EventType::PitchBend => 32767, _ => 0, } } } -#[derive(Debug,Default)] +#[derive(Debug, Default)] pub struct Event<'a> { pub r#type: EventType, pub channel: u8, @@ -86,7 +81,7 @@ pub struct Event<'a> { pub timestamp: Option, } -#[derive(Debug,Clone,Default)] +#[derive(Debug, Clone, Default)] pub struct EventBuf { pub r#type: EventType, pub channel: u8, @@ -105,7 +100,7 @@ pub struct EventEnv { pub value: String, } -#[derive(Clone,Debug)] +#[derive(Clone, Debug)] struct EventEnvRef<'a> { pub channel: &'a str, pub id: &'a str, @@ -115,11 +110,17 @@ struct EventEnvRef<'a> { pub value: &'a str, } - impl<'a> std::fmt::Display for Event<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{{ \"type\": \"{}\", \"channel\": {}, \"id\": {}, \"value\": {}, \"raw\": \"{}\" }}", - self.r#type, self.channel, self.id, self.value, bytes_to_strhex(self.raw, " ")) + write!( + f, + "{{ \"type\": \"{}\", \"channel\": {}, \"id\": {}, \"value\": {}, \"raw\": \"{}\" }}", + self.r#type, + self.channel, + self.id, + self.value, + bytes_to_strhex(self.raw, " ") + ) } } @@ -157,11 +158,10 @@ impl Into for Event<'_> { impl From for EventType { fn from(v: u8) -> Self { - if ! (0b1000..=0b1111).contains(&v) { + if !(0b1000..=0b1111).contains(&v) { // not in defined space: unknown EventType::Unknown - } - else { + } else { // safe since all valid cases are defined unsafe { std::mem::transmute(v) } } @@ -195,19 +195,23 @@ impl<'a> Event<'a> { event_to_key(self.r#type, self.channel, self.id) } - pub fn make_env(&self, remap: Option<&Remapper>, float: bool) -> Result - { + pub fn make_env(&self, remap: Option<&Remapper>, float: bool) -> Result { Ok(EventEnv { channel: self.channel.to_string(), id: self.id.to_string(), rawvalue: self.value.to_string(), raw: bytes_to_strhex(self.raw, " "), - timestamp: self.timestamp.unwrap_or(SystemTime::now()).duration_since(SystemTime::UNIX_EPOCH)?.as_secs_f64().to_string(), - value: match (remap,float) { - (Some(r),true) => r.remap(self.value as f64).to_string(), - (Some(r),false) => r.remap_to::(self.value as f64).unwrap().to_string(), + timestamp: self + .timestamp + .unwrap_or(SystemTime::now()) + .duration_since(SystemTime::UNIX_EPOCH)? + .as_secs_f64() + .to_string(), + value: match (remap, float) { + (Some(r), true) => r.remap(self.value as f64).to_string(), + (Some(r), false) => r.remap_to::(self.value as f64).unwrap().to_string(), _ => self.value.to_string(), - } + }, }) } } @@ -218,20 +222,25 @@ impl<'a> From<&'a [u8]> for Event<'a> { eprintln!("warning: empty signal"); return Default::default(); } - let event_type = EventType::from(v[0]/16); - let channel = if event_type.has_channel() { v[0]%16 } else { 0 }; + let event_type = EventType::from(v[0] / 16); + let channel = if event_type.has_channel() { + v[0] % 16 + } else { + 0 + }; let (id, value) = match event_type { - EventType::PitchBend => { - (0, (v[2] as u16)*256 + (v[1] as u16) ) - }, + EventType::PitchBend => (0, (v[2] as u16) * 256 + (v[1] as u16)), EventType::Unknown => { eprintln!("warning: unknown signal type: {}", v[0]); - (0,0) + (0, 0) } - EventType::System => (0,0), - EventType::ChannelPressure => (0,v[1] as u16), - EventType::ProgramChange => (v[1],0), - EventType::NoteOn | EventType::NoteOff | EventType::PolyphonicKeyPressure | EventType::Controller => (v[1],(v[2] as u16)), + EventType::System => (0, 0), + EventType::ChannelPressure => (0, v[1] as u16), + EventType::ProgramChange => (v[1], 0), + EventType::NoteOn + | EventType::NoteOff + | EventType::PolyphonicKeyPressure + | EventType::Controller => (v[1], (v[2] as u16)), }; Event { r#type: event_type, @@ -245,19 +254,41 @@ impl<'a> From<&'a [u8]> for Event<'a> { } impl EventEnv { - pub fn to_map(self, m: Option<&EventEnvMap>) -> HashMap<&str,String> { + pub fn to_map(self, m: Option<&EventEnvMap>) -> HashMap<&str, String> { let mut r = HashMap::new(); let keys: EventEnvRef = match m { - Some(v) => { - EventEnvRef { - channel: v.channel.as_ref().map(|x| &x[..]).unwrap_or(EVENT_ENV_DEFAULT.channel), - id: v.id.as_ref().map(|x| &x[..]).unwrap_or(EVENT_ENV_DEFAULT.id), - raw: v.raw.as_ref().map(|x| &x[..]).unwrap_or(EVENT_ENV_DEFAULT.raw), - rawvalue: v.rawvalue.as_ref().map(|x| &x[..]).unwrap_or(EVENT_ENV_DEFAULT.rawvalue), - timestamp: v.timestamp.as_ref().map(|x| &x[..]).unwrap_or(EVENT_ENV_DEFAULT.timestamp), - value: v.value.as_ref().map(|x| &x[..]).unwrap_or(EVENT_ENV_DEFAULT.value), - } - } + Some(v) => EventEnvRef { + channel: v + .channel + .as_ref() + .map(|x| &x[..]) + .unwrap_or(EVENT_ENV_DEFAULT.channel), + id: v + .id + .as_ref() + .map(|x| &x[..]) + .unwrap_or(EVENT_ENV_DEFAULT.id), + raw: v + .raw + .as_ref() + .map(|x| &x[..]) + .unwrap_or(EVENT_ENV_DEFAULT.raw), + rawvalue: v + .rawvalue + .as_ref() + .map(|x| &x[..]) + .unwrap_or(EVENT_ENV_DEFAULT.rawvalue), + timestamp: v + .timestamp + .as_ref() + .map(|x| &x[..]) + .unwrap_or(EVENT_ENV_DEFAULT.timestamp), + value: v + .value + .as_ref() + .map(|x| &x[..]) + .unwrap_or(EVENT_ENV_DEFAULT.value), + }, _ => EVENT_ENV_DEFAULT.clone(), }; r.insert(keys.channel, self.channel); diff --git a/src/eventmap.rs b/src/eventmap.rs index b61ef19..b3b9747 100644 --- a/src/eventmap.rs +++ b/src/eventmap.rs @@ -1,24 +1,27 @@ use std::collections::HashMap; -use crate::config::{EventConfig,DeviceConfig}; -use crate::event::{EventType,Event}; +use crate::config::{DeviceConfig, EventConfig}; +use crate::event::{Event, EventType}; use crate::Error; -#[derive(Debug,Default)] +#[derive(Debug, Default)] pub struct EventMap<'a> { pub map: HashMap>, } fn event_to_key(r#type: EventType, channel: u8, id: u8) -> u32 { - (r#type as u32)*256*256 + (channel as u32)*256 + (id as u32) + (r#type as u32) * 256 * 256 + (channel as u32) * 256 + (id as u32) } pub fn count_events(events: &[EventConfig]) -> usize { - events.iter().map(|x| { - let nchannel = x.channel.len(); - let nid = x.id.len(); - nchannel * nid - }).sum() + events + .iter() + .map(|x| { + let nchannel = x.channel.len(); + let nid = x.id.len(); + nchannel * nid + }) + .sum() } impl<'a> EventMap<'a> { @@ -29,8 +32,7 @@ impl<'a> EventMap<'a> { let key = event_to_key(event.r#type, channel, id); if let Some(v) = self.map.get_mut(&key) { v.push(event); - } - else { + } else { self.map.insert(key, Vec::from([event])); } } @@ -38,13 +40,15 @@ impl<'a> EventMap<'a> { } } - pub fn run_event(&self, event: &Event) -> Result<(), Error > { + pub fn run_event(&self, event: &Event) -> Result<(), Error> { let key = event_to_key(event.r#type, event.channel, event.id); if let Some(v) = self.map.get(&key) { for ev in v { if ev.match_value(event) { for r in &ev.run { - let env = event.make_env(ev.remap.as_ref(), ev.float )?.to_map(r.envconf.as_ref()); + let env = event + .make_env(ev.remap.as_ref(), ev.float)? + .to_map(r.envconf.as_ref()); r.run(env)?; } } @@ -58,12 +62,13 @@ impl<'a> From<&'a [EventConfig]> for EventMap<'a> { fn from(events: &'a [EventConfig]) -> Self { // init hashmap with size for optimizing let size = count_events(events); - let mut ret = EventMap { map: HashMap::with_capacity(size) }; + let mut ret = EventMap { + map: HashMap::with_capacity(size), + }; // insert references ret.add_events(events); ret } - } impl<'a> From<&'a DeviceConfig> for EventMap<'a> { @@ -71,12 +76,13 @@ impl<'a> From<&'a DeviceConfig> for EventMap<'a> { // init hashmap with size for optimizing let size = count_events(device.events.as_ref().map(|x| &x[..]).unwrap_or(&[])); //let size = events.iter().map(|x| x.channels.len()*x.ids.len() ).sum(); - let mut ret = EventMap { map: HashMap::with_capacity(size) }; + let mut ret = EventMap { + map: HashMap::with_capacity(size), + }; // insert references if let Some(x) = device.events.as_ref() { ret.add_events(x); } ret } - } diff --git a/src/main.rs b/src/main.rs index d1aabf0..e64e639 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,12 @@ -#[macro_use] -extern crate enum_display_derive; - +pub mod cli; pub mod config; -pub mod run; +pub mod constant; +pub mod error; pub mod event; pub mod eventmap; pub mod midi; +pub mod run; pub mod util; -pub mod cli; -pub mod error; -pub mod constant; type Error = error::Error; @@ -17,33 +14,27 @@ use std::path::Path; use clap::Parser; -use config::Config; use cli::Cli; +use config::Config; use midi::MidiHandler; fn main() { let c = Cli::parse(); - + if c.list { let mut handler = err_handle(MidiHandler::new(constant::CLIENT_NAME)); - err_handle( - handler.builder_handler(run::ListDevicesBuilder, ()) - ); + err_handle(handler.builder_handler(run::ListDevicesBuilder, ())); return; } - let map_file = err_handle( - c.map_file.ok_or(Error::NoArgument) - ); + let map_file = err_handle(c.map_file.ok_or(Error::NoArgument)); loop { - err_handle( - run_file(&map_file) - ); + err_handle(run_file(&map_file)); } } -fn err_handle(r: Result) -> T +fn err_handle(r: Result) -> T where - E: std::fmt::Display + E: std::fmt::Display, { match r { Ok(v) => v, @@ -56,7 +47,7 @@ where fn run_file(filepath: &Path) -> Result<(), Error> { println!("Load file {}", filepath.to_str().unwrap_or("")); - let dat = std::fs::read( filepath )?; + let dat = std::fs::read(filepath)?; let conf = Config::try_from(&dat[..])?; let mut handler = match conf.driver { Some(v) => MidiHandler::new_with_driver(constant::CLIENT_NAME, v), diff --git a/src/midi/backend/alsa.rs b/src/midi/backend/alsa.rs index dd893d2..ab2d6d7 100644 --- a/src/midi/backend/alsa.rs +++ b/src/midi/backend/alsa.rs @@ -1,21 +1,24 @@ -extern crate libc; extern crate alsa; +extern crate libc; +use std::ffi::{CStr, CString}; use std::str::FromStr; -use std::{mem, thread}; -use std::ffi::{CString, CStr}; -use std::time::SystemTime; use std::sync::mpsc; +use std::time::SystemTime; +use std::{mem, thread}; -use crate::midi::{MidiInput,MidiPort,PortFilter}; use crate::error::Error; +use crate::midi::{MidiInput, MidiPort, PortFilter}; use crate::util::InternalTryFrom; -use alsa::{Seq, Direction}; -use alsa::seq::{ClientIter, PortIter, MidiEvent, PortInfo, PortSubscribe, Addr, QueueTempo, EventType, PortCap, PortType}; +use alsa::seq::{ + Addr, ClientIter, EventType, MidiEvent, PortCap, PortInfo, PortIter, PortSubscribe, PortType, + QueueTempo, +}; +use alsa::{Direction, Seq}; use thiserror::Error; -#[derive(Debug,Clone,PartialEq,Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct DeviceAddr(Addr); const ANNOUNCE_ADDR: &str = "System:Announce"; @@ -39,15 +42,16 @@ impl FromStr for DeviceAddr { // todo!() // let mut osep = ; if let Some(sep) = s.find(':') { - let (p1,p2) = (&s[..sep], &s[sep+1..] ); - Ok(DeviceAddr( - Addr { - client: p1.parse().map_err(|_| AlsaError::AddrParse(s.to_string()))?, - port: p2.parse().map_err(|_| AlsaError::AddrParse(s.to_string()))?, - } - )) - } - else { + let (p1, p2) = (&s[..sep], &s[sep + 1..]); + Ok(DeviceAddr(Addr { + client: p1 + .parse() + .map_err(|_| AlsaError::AddrParse(s.to_string()))?, + port: p2 + .parse() + .map_err(|_| AlsaError::AddrParse(s.to_string()))?, + })) + } else { Err(AlsaError::AddrParse(s.to_string())) } } @@ -72,7 +76,8 @@ impl DeviceAddr { } pub fn get_ports(s: &Seq, capability: PortCap) -> Vec { - ClientIter::new(s).flat_map(|c| PortIter::new(s, c.get_client())) + ClientIter::new(s) + .flat_map(|c| PortIter::new(s, c.get_client())) .filter(|p| p.get_capability().contains(capability)) .collect() } @@ -83,7 +88,7 @@ mod helpers { } } -#[derive(Error,Debug)] +#[derive(Error, Debug)] pub enum AlsaError { #[error(transparent)] ALSA(#[from] alsa::Error), @@ -99,7 +104,7 @@ pub struct MidiInputAlsa { subscription: Option, connect_addr: Option, start_time: Option, - stop_trigger: [i32;2], + stop_trigger: [i32; 2], } impl Drop for MidiInputAlsa { @@ -119,10 +124,11 @@ impl MidiInputAlsa { } } - fn init_queue(&mut self) -> Result { // Create the input queue - let queue_id = self.seq.alloc_named_queue(unsafe { CStr::from_bytes_with_nul_unchecked(b"midir queue\0") })?; + let queue_id = self + .seq + .alloc_named_queue(unsafe { CStr::from_bytes_with_nul_unchecked(b"midir queue\0") })?; // Set arbitrary tempo (mm=100) and resolution (240) let qtempo = QueueTempo::empty()?; qtempo.set_tempo(600_000); @@ -130,7 +136,6 @@ impl MidiInputAlsa { self.seq.set_queue_tempo(queue_id, &qtempo)?; let _ = self.seq.drain_output(); - Ok(queue_id) } @@ -159,18 +164,20 @@ impl MidiInputAlsa { } } - fn close_internal(&mut self) - { + fn close_internal(&mut self) { if let Some(ref subscription) = self.subscription { - let _ = self.seq.unsubscribe_port(subscription.get_sender(), subscription.get_dest()); + let _ = self + .seq + .unsubscribe_port(subscription.get_sender(), subscription.get_dest()); } // Stop and free the input queue - let _ = self.seq.control_queue(self.queue_id, EventType::Stop, 0, None); + let _ = self + .seq + .control_queue(self.queue_id, EventType::Stop, 0, None); let _ = self.seq.drain_output(); let _ = self.seq.free_queue(self.queue_id); - for fd in self.stop_trigger { if fd >= 0 { unsafe { self::libc::close(fd) }; @@ -179,16 +186,24 @@ impl MidiInputAlsa { } fn signal_stop_input_internal(stop_trigger: i32) -> Result<(), Error> { - if unsafe { self::libc::write(stop_trigger, &false as *const bool as *const _, mem::size_of::() as self::libc::size_t) } == -1 { + if unsafe { + self::libc::write( + stop_trigger, + &false as *const bool as *const _, + mem::size_of::() as self::libc::size_t, + ) + } == -1 + { Err(Error::Pipe) - } - else { + } else { Ok(()) } } fn alsa_input_handler(&mut self, callback: F, mut userdata: D) -> Result<(), Error> - where F: Fn(&Self, alsa::seq::Event, &mut D) -> Result { + where + F: Fn(&Self, alsa::seq::Event, &mut D) -> Result, + { // fd defitions use self::alsa::PollDescriptors; use self::libc::pollfd; @@ -202,7 +217,7 @@ impl MidiInputAlsa { // make poll fds let poll_desc_info = (&self.seq, Some(Direction::Capture)); - let mut poll_fds = vec![INVALID_POLLFD; poll_desc_info.count()+1]; + let mut poll_fds = vec![INVALID_POLLFD; poll_desc_info.count() + 1]; poll_fds[0] = pollfd { fd: self.stop_trigger[0], events: self::libc::POLLIN, @@ -217,7 +232,13 @@ impl MidiInputAlsa { // Read stop event from triggerer if poll_fds[0].revents & self::libc::POLLIN != 0 { let mut pollread = false; - let _res = unsafe { self::libc::read(poll_fds[0].fd, &mut pollread as *mut bool as *mut libc::c_void, mem::size_of::() as self::libc::size_t) }; + let _res = unsafe { + self::libc::read( + poll_fds[0].fd, + &mut pollread as *mut bool as *mut libc::c_void, + mem::size_of::() as self::libc::size_t, + ) + }; if !pollread { break; } @@ -243,7 +264,7 @@ impl MidiInputAlsa { Err(e) => { eprintln!("ALSA CALLBACK ERROR: {}", e); eprintln!("continuing execution"); - }, + } } } Ok(()) @@ -251,13 +272,13 @@ impl MidiInputAlsa { fn binary_input_handler(&mut self, callback: F, userdata: D) -> Result<(), Error> where - F: Fn(&Self, Option, &[u8], &mut D) -> Result<(),Error> + Send + F: Fn(&Self, Option, &[u8], &mut D) -> Result<(), Error> + Send, { let decoder = MidiEvent::new(0)?; decoder.enable_running_status(false); - let message = vec!(); - let buffer: [u8;12] = [0;12]; + let message = vec![]; + let buffer: [u8; 12] = [0; 12]; let continue_sysex = false; let ts = match self.start_time.as_ref() { @@ -265,48 +286,61 @@ impl MidiInputAlsa { _ => SystemTime::now(), }; - self.alsa_input_handler(|s, mut ev, (message, buffer, continue_sysex, userdata)| { - if !*continue_sysex { message.clear() } - - let do_decode = match ev.get_type() { - EventType::PortSubscribed | - EventType::PortUnsubscribed | - EventType::Qframe | - EventType::Tick | - EventType::Clock | - EventType::Sensing => false, - EventType::Sysex => { - message.extend_from_slice(ev.get_ext().unwrap()); - *continue_sysex = *message.last().unwrap() != 0xF7; - false + self.alsa_input_handler( + |s, mut ev, (message, buffer, continue_sysex, userdata)| { + if !*continue_sysex { + message.clear() } - _ => true - }; - // NOTE: SysEx messages have already been "decoded" at this point! - if do_decode { - let nbytes = decoder.decode(buffer, &mut ev).map_err(|_| AlsaError::Decode)?; - if nbytes > 0 { - message.extend_from_slice(&buffer[0..nbytes+1]); + let do_decode = match ev.get_type() { + EventType::PortSubscribed + | EventType::PortUnsubscribed + | EventType::Qframe + | EventType::Tick + | EventType::Clock + | EventType::Sensing => false, + EventType::Sysex => { + message.extend_from_slice(ev.get_ext().unwrap()); + *continue_sysex = *message.last().unwrap() != 0xF7; + false + } + _ => true, + }; + + // NOTE: SysEx messages have already been "decoded" at this point! + if do_decode { + let nbytes = decoder + .decode(buffer, &mut ev) + .map_err(|_| AlsaError::Decode)?; + if nbytes > 0 { + message.extend_from_slice(&buffer[0..nbytes + 1]); + } } - } - if message.is_empty() || *continue_sysex { return Ok(false); } + if message.is_empty() || *continue_sysex { + return Ok(false); + } - let ts: Option = ev.get_time().map(|v| ts+v); - (callback)(s, ts, message, userdata)?; - Ok(false) - } - , (message, buffer, continue_sysex, userdata))?; + let ts: Option = ev.get_time().map(|v| ts + v); + (callback)(s, ts, message, userdata)?; + Ok(false) + }, + (message, buffer, continue_sysex, userdata), + )?; Ok(()) } - fn threaded_alsa_input(&mut self, callback: F, (ts, rs): (mpsc::Sender, mpsc::Receiver), userdata: D) -> Result<(),Error> + fn threaded_alsa_input( + &mut self, + callback: F, + (ts, rs): (mpsc::Sender, mpsc::Receiver), + userdata: D, + ) -> Result<(), Error> where F: Fn(&Self, alsa::seq::Event, &mut D) -> Result + Send, D: Send, { - thread::scope( |sc| -> Result<(), Error> { + thread::scope(|sc| -> Result<(), Error> { let stop_trigger = self.stop_trigger[1]; let t = sc.spawn(move || -> Result<(), Error> { let userdata = userdata; @@ -316,20 +350,26 @@ impl MidiInputAlsa { }); match rs.recv()? { true => Self::signal_stop_input_internal(stop_trigger)?, - false => () + false => (), }; t.join().expect("unexpected thread error")?; Ok(()) }) } - fn threaded_handler(&mut self, handler: H, callback: F, (ts, rs): (mpsc::Sender, mpsc::Receiver), userdata: D) -> Result<(),Error> + fn threaded_handler( + &mut self, + handler: H, + callback: F, + (ts, rs): (mpsc::Sender, mpsc::Receiver), + userdata: D, + ) -> Result<(), Error> where - H: Fn(&mut Self, F,D) -> Result<(), Error> + Send, - F: Fn(&Self, T, &RF, &mut D) -> Result + Send, + H: Fn(&mut Self, F, D) -> Result<(), Error> + Send, + F: Fn(&Self, T, &RF, &mut D) -> Result + Send, D: Send, { - thread::scope( |sc| -> Result<(), Error> { + thread::scope(|sc| -> Result<(), Error> { let stop_trigger = self.stop_trigger[1]; let t = sc.spawn(move || -> Result<(), Error> { let userdata = userdata; @@ -339,7 +379,7 @@ impl MidiInputAlsa { }); match rs.recv()? { true => Self::signal_stop_input_internal(stop_trigger)?, - false => () + false => (), }; t.join().expect("unexpected thread error")?; Ok(()) @@ -361,7 +401,7 @@ impl MidiInput for MidiInputAlsa { subscription: None, connect_addr: None, start_time: None, - stop_trigger: [-1,-1], + stop_trigger: [-1, -1], }) } @@ -371,26 +411,29 @@ impl MidiInput for MidiInputAlsa { } fn ports(&self) -> Result>, Error> { - get_ports(&self.seq, PortCap::READ | PortCap::SUBS_READ).iter().map(|x| -> Result, Error> { - let cinfo = self.seq.get_any_client_info(x.get_client())?; - Ok(MidiPort { - name: cinfo.get_name()?.to_string()+":"+x.get_name()?, - addr: x.addr().into(), + get_ports(&self.seq, PortCap::READ | PortCap::SUBS_READ) + .iter() + .map(|x| -> Result, Error> { + let cinfo = self.seq.get_any_client_info(x.get_client())?; + Ok(MidiPort { + name: cinfo.get_name()?.to_string() + ":" + x.get_name()?, + addr: x.addr().into(), + }) }) - }).collect() + .collect() } - fn filter_ports(&self, mut ports: Vec>, filter: PortFilter) -> Vec> { - ports.retain( - |p| { - match &filter { - PortFilter::All => true, - PortFilter::Name(s) => p.name.contains(s), - PortFilter::Regex(s) => s.is_match(&p.name), - PortFilter::Addr(s) => p.addr == *s, - } - } - ); + fn filter_ports( + &self, + mut ports: Vec>, + filter: PortFilter, + ) -> Vec> { + ports.retain(|p| match &filter { + PortFilter::All => true, + PortFilter::Name(s) => p.name.contains(s), + PortFilter::Regex(s) => s.is_match(&p.name), + PortFilter::Addr(s) => p.addr == *s, + }); ports } @@ -403,7 +446,10 @@ impl MidiInput for MidiInputAlsa { let sub = PortSubscribe::empty()?; sub.set_sender(src_pinfo.addr()); - sub.set_dest(Addr { client: self.seq.client_id()?, port: vport}); + sub.set_dest(Addr { + client: self.seq.client_id()?, + port: vport, + }); self.seq.subscribe_port(&sub)?; self.subscription = Some(sub); self.init_trigger()?; @@ -413,26 +459,35 @@ impl MidiInput for MidiInputAlsa { Ok(()) } - fn device_events(&mut self, ts: mpsc::Sender>>, (tss, rss): (mpsc::Sender, mpsc::Receiver)) -> Result<(), Error> { + fn device_events( + &mut self, + ts: mpsc::Sender>>, + (tss, rss): (mpsc::Sender, mpsc::Receiver), + ) -> Result<(), Error> { let ports = self.ports()?; let port = self.filter_ports(ports, PortFilter::Name(ANNOUNCE_ADDR.to_string())); self.connect(&port[0].addr, CLIENT_NAME_ANNOUNCE)?; - self.threaded_alsa_input(move |s: &Self, ev: alsa::seq::Event, _| -> Result { - // handle disconnect event on watched port - match ev.get_type() { - EventType::PortStart => { - if let Some(a) = ev.get_data::() { - let p = s.ports()?; - let pp = s.filter_ports(p, PortFilter::Addr( a.into() ) ); - if !pp.is_empty() { - ts.send(Some(pp[0].clone())).expect("unexpected send() error"); - } - }; - Ok(false) + self.threaded_alsa_input( + move |s: &Self, ev: alsa::seq::Event, _| -> Result { + // handle disconnect event on watched port + match ev.get_type() { + EventType::PortStart => { + if let Some(a) = ev.get_data::() { + let p = s.ports()?; + let pp = s.filter_ports(p, PortFilter::Addr(a.into())); + if !pp.is_empty() { + ts.send(Some(pp[0].clone())) + .expect("unexpected send() error"); + } + }; + Ok(false) + } + _ => Ok(false), } - _ => Ok(false), - } - }, (tss, rss), ())?; + }, + (tss, rss), + (), + )?; self.close_internal(); Ok(()) } @@ -441,15 +496,24 @@ impl MidiInput for MidiInputAlsa { Self::signal_stop_input_internal(self.stop_trigger[1]) } - fn handle_input(&mut self, callback: F, (ts, rs): (mpsc::Sender, mpsc::Receiver), userdata: D) -> Result<(), Error> + fn handle_input( + &mut self, + callback: F, + (ts, rs): (mpsc::Sender, mpsc::Receiver), + userdata: D, + ) -> Result<(), Error> where F: Fn(&Self, &[u8], Option, &mut D) + Send + Sync, D: Send, { - self.threaded_handler(Self::binary_input_handler, - |s, t, m, d| -> Result<(),Error> { - callback(s,m,t,d); + self.threaded_handler( + Self::binary_input_handler, + |s, t, m, d| -> Result<(), Error> { + callback(s, m, t, d); Ok(()) - }, (ts, rs), userdata) + }, + (ts, rs), + userdata, + ) } } diff --git a/src/midi/builder.rs b/src/midi/builder.rs index d636d24..2cc17a3 100644 --- a/src/midi/builder.rs +++ b/src/midi/builder.rs @@ -1,13 +1,12 @@ use crate::util::InternalTryFrom; -pub use super::input::{MidiInput,MidiInputHandler}; +pub use super::input::{MidiInput, MidiInputHandler}; pub trait Builder { fn build(&self) -> fn(&T, D) -> R where - T: MidiInputHandler+MidiInput+Send+'static, - ::DeviceAddr: std::fmt::Display+'static+InternalTryFrom, - ; + T: MidiInputHandler + MidiInput + Send + 'static, + ::DeviceAddr: std::fmt::Display + 'static + InternalTryFrom; } macro_rules! builder { @@ -16,12 +15,13 @@ macro_rules! builder { impl Builder<$intype, $rettype> for $name { fn build(&self) -> fn(&T, $intype) -> $rettype where - T: MidiInputHandler+Send+'static, - ::DeviceAddr: std::fmt::Display+'static+InternalTryFrom, + T: MidiInputHandler + Send + 'static, + ::DeviceAddr: + std::fmt::Display + 'static + InternalTryFrom, { $fct } } }; } -pub(crate) use builder; \ No newline at end of file +pub(crate) use builder; diff --git a/src/midi/driver.rs b/src/midi/driver.rs index 52b0337..1a8075b 100644 --- a/src/midi/driver.rs +++ b/src/midi/driver.rs @@ -1,6 +1,6 @@ use serde::Deserialize; -#[derive(Deserialize,Debug,Clone,Copy,Eq,PartialEq)] +#[derive(Deserialize, Debug, Clone, Copy, Eq, PartialEq)] #[serde(rename_all = "lowercase")] pub enum MidiDriver { ALSA, diff --git a/src/midi/input.rs b/src/midi/input.rs index f7806fd..96e9bad 100644 --- a/src/midi/input.rs +++ b/src/midi/input.rs @@ -1,57 +1,83 @@ -use crate::util::InternalTryFrom; -use crate::{Error, constant}; use crate::config::DeviceConfig; -use crate::eventmap::EventMap; use crate::event::{Event, EventBuf}; +use crate::eventmap::EventMap; +use crate::util::InternalTryFrom; +use crate::{constant, Error}; use std::str::FromStr; +use std::sync::{mpsc, Arc, Mutex}; use std::thread; -use std::time::{SystemTime, Instant}; -use std::sync::{mpsc, Mutex, Arc}; +use std::time::{Instant, SystemTime}; use queues::{CircularBuffer, IsQueue}; -use super::{PortFilter, MidiPort}; +use super::{MidiPort, PortFilter}; pub trait MidiInput where - ::DeviceAddr: Clone+Send+FromStr, - ::DeviceAddr: InternalTryFrom + ::DeviceAddr: Clone + Send + FromStr, + ::DeviceAddr: InternalTryFrom, { type DeviceAddr; fn new(client_name: &str) -> Result - where Self: Sized; + where + Self: Sized; fn close(self) -> Result<(), Error>; fn ports(&self) -> Result>, Error>; - fn filter_ports(&self, ports: Vec>, filter: PortFilter) -> Vec>; + fn filter_ports( + &self, + ports: Vec>, + filter: PortFilter, + ) -> Vec>; fn connect(&mut self, port_addr: &Self::DeviceAddr, port_name: &str) -> Result<(), Error>; - fn device_events(&mut self, ts: mpsc::Sender>>, ss: (mpsc::Sender, mpsc::Receiver)) -> Result<(), Error>; + fn device_events( + &mut self, + ts: mpsc::Sender>>, + ss: (mpsc::Sender, mpsc::Receiver), + ) -> Result<(), Error>; fn signal_stop_input(&self) -> Result<(), Error>; - fn handle_input(&mut self, callback: F, rts: (mpsc::Sender, mpsc::Receiver), userdata: D) -> Result<(), Error> + fn handle_input( + &mut self, + callback: F, + rts: (mpsc::Sender, mpsc::Receiver), + userdata: D, + ) -> Result<(), Error> where F: Fn(&Self, &[u8], Option, &mut D) + Send + Sync, - D: Send, - ; + D: Send; } -pub trait MidiInputHandler +pub trait MidiInputHandler where Self: Sized, - ::DeviceAddr: Clone+Send+FromStr, + ::DeviceAddr: Clone + Send + FromStr, { type DeviceAddr; fn new(client_name: &str) -> Result; fn ports(&self) -> Result>, Error>; - fn try_connect(&self, port: MidiPort, filter: PortFilter ) -> Result, Error>; - fn run(&mut self, conf: &DeviceConfig, eventmap: &EventMap, trs: (mpsc::Sender, mpsc::Receiver)) -> Result<(), Error>; - fn device_events(&mut self, ts: mpsc::Sender>>, ss: (mpsc::Sender,mpsc::Receiver)) -> Result<(), Error>; + fn try_connect( + &self, + port: MidiPort, + filter: PortFilter, + ) -> Result, Error>; + fn run( + &mut self, + conf: &DeviceConfig, + eventmap: &EventMap, + trs: (mpsc::Sender, mpsc::Receiver), + ) -> Result<(), Error>; + fn device_events( + &mut self, + ts: mpsc::Sender>>, + ss: (mpsc::Sender, mpsc::Receiver), + ) -> Result<(), Error>; } // Generic implementation @@ -62,7 +88,6 @@ where ::DeviceAddr: FromStr, { type DeviceAddr = T::DeviceAddr; - fn new(client_name: &str) -> Result { MidiInput::new(client_name) @@ -72,7 +97,11 @@ where MidiInput::ports(self) } - fn try_connect(&self, port: MidiPort, filter: PortFilter ) -> Result, Error> { + fn try_connect( + &self, + port: MidiPort, + filter: PortFilter, + ) -> Result, Error> { let portmap = self.ports()?; let pv = self.filter_ports(portmap, PortFilter::Addr(port.addr)); let pv = self.filter_ports(pv, filter); @@ -81,35 +110,44 @@ where let mut v = T::new(constant::CLIENT_NAME_HANDLER)?; v.connect(&port.addr, constant::CLIENT_NAME_HANDLER)?; Ok(Some(v)) - } - else { + } else { Ok(None) } } - fn device_events(&mut self, ts: mpsc::Sender>>, ss: (mpsc::Sender,mpsc::Receiver)) -> Result<(), Error> { + fn device_events( + &mut self, + ts: mpsc::Sender>>, + ss: (mpsc::Sender, mpsc::Receiver), + ) -> Result<(), Error> { self.device_events(ts, ss) } - fn run(&mut self, conf: &DeviceConfig, eventmap: &EventMap, (ts, rs): (mpsc::Sender, mpsc::Receiver)) -> Result<(), Error> { + fn run( + &mut self, + conf: &DeviceConfig, + eventmap: &EventMap, + (ts, rs): (mpsc::Sender, mpsc::Receiver), + ) -> Result<(), Error> { thread::scope(|s| -> Result<(), Error> { - // parking signal for runner, true = stop - let (pts,prs) = mpsc::channel::(); - + let (pts, prs) = mpsc::channel::(); + // event queue populated by the main thread and consumed by the exec thread - let evq = Arc::new(Mutex::new(CircularBuffer::::new(conf.queue_length))); - + let evq = Arc::new(Mutex::new(CircularBuffer::::new( + conf.queue_length, + ))); + // background execution loop let rq = evq.clone(); - let exec_thread = s.spawn(move || -> Result<(),Error> { + let exec_thread = s.spawn(move || -> Result<(), Error> { loop { if prs.recv()? { break; } loop { // nest the lock into a scope to release it before run - let (ev,start): (EventBuf,Instant) = { + let (ev, start): (EventBuf, Instant) = { let mut evq = rq.lock().unwrap(); if evq.size() > 0 { (evq.remove().unwrap(), Instant::now()) @@ -117,7 +155,9 @@ where break; } }; - eventmap.run_event(&ev.as_event()).unwrap_or_else(|e| eprintln!("ERROR: error on run: {}", e) ); + eventmap + .run_event(&ev.as_event()) + .unwrap_or_else(|e| eprintln!("ERROR: error on run: {}", e)); // wait until interval has been reached let elapsed_time = start.elapsed(); if elapsed_time < conf.interval { @@ -127,23 +167,26 @@ where } Ok(()) }); - - self.handle_input(|_,m,t,(evq,pts)| { - let mut event: EventBuf = Event::from(m).into(); - event.timestamp = t; - if conf.log { - println!("{}: event: {}", constant::CLIENT_NAME, event); - } - let mut evq = evq.lock().unwrap(); - evq.add(event).unwrap(); - pts.send(false).expect("unexpected write error"); - }, (ts,rs), (evq,pts.clone()))?; - + + self.handle_input( + |_, m, t, (evq, pts)| { + let mut event: EventBuf = Event::from(m).into(); + event.timestamp = t; + if conf.log { + println!("{}: event: {}", constant::CLIENT_NAME, event); + } + let mut evq = evq.lock().unwrap(); + evq.add(event).unwrap(); + pts.send(false).expect("unexpected write error"); + }, + (ts, rs), + (evq, pts.clone()), + )?; + pts.send(true).expect("unexpected write error"); let _ = exec_thread.join(); - + Ok(()) - })?; Ok(()) } diff --git a/src/midi/mod.rs b/src/midi/mod.rs index dcbd55e..c832612 100644 --- a/src/midi/mod.rs +++ b/src/midi/mod.rs @@ -1,20 +1,20 @@ pub mod backend; -pub mod port; -pub mod portfilter; -pub mod input; pub mod builder; pub mod driver; +pub mod input; +pub mod port; +pub mod portfilter; use crate::Error; extern crate libc; -pub use driver::MidiDriver; pub use builder::Builder; +pub use driver::MidiDriver; +pub use input::{MidiInput, MidiInputHandler}; pub use port::MidiPort; pub use portfilter::PortFilter; -pub use input::{MidiInput,MidiInputHandler}; pub enum MidiHandler { ALSA(backend::MidiInputAlsa), @@ -35,7 +35,7 @@ impl MidiHandler { // wrap generic functions into builder because functions with generic traits cannot be passed as arguments pub fn builder_handler(&mut self, builder: B, data: D) -> R where - B: Builder, + B: Builder, D: Send, { match self { diff --git a/src/midi/port.rs b/src/midi/port.rs index 55a1db9..904bb76 100644 --- a/src/midi/port.rs +++ b/src/midi/port.rs @@ -1,21 +1,19 @@ use std::fmt::{Display, Formatter}; - -#[derive(Eq,PartialEq,Debug,Clone)] +#[derive(Eq, PartialEq, Debug, Clone)] pub struct MidiPort where - T: Clone + T: Clone, { pub name: String, pub addr: T, } - impl Display for MidiPort where - T: Display+Clone + T: Display + Clone, { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}\t{}", self.addr, self.name) } -} \ No newline at end of file +} diff --git a/src/midi/portfilter.rs b/src/midi/portfilter.rs index 4952473..447439c 100644 --- a/src/midi/portfilter.rs +++ b/src/midi/portfilter.rs @@ -1,18 +1,16 @@ -use crate::Error; -use crate::config::DeviceConfig; use crate::config::device::Identifier; +use crate::config::DeviceConfig; use crate::util::InternalTryFrom; +use crate::Error; - -#[derive(Debug,Clone)] -pub enum PortFilter{ +#[derive(Debug, Clone)] +pub enum PortFilter { All, Name(String), Regex(regex::Regex), Addr(T), } - impl InternalTryFrom<&DeviceConfig> for PortFilter where T: InternalTryFrom, @@ -25,4 +23,4 @@ where Identifier::Addr(s) => PortFilter::Addr(T::i_try_from(s.to_string())?), }) } -} \ No newline at end of file +} diff --git a/src/run.rs b/src/run.rs index 5c49c2d..6312bfc 100644 --- a/src/run.rs +++ b/src/run.rs @@ -1,29 +1,36 @@ use std::sync::mpsc; +use std::sync::{Arc, Mutex}; use std::thread; -use std::sync::{Mutex,Arc}; use libc::SIGUSR1; use signal_hook::iterator::Signals; -use crate::util::InternalTryFrom; -use crate::{Error, constant}; -use crate::midi::{PortFilter,MidiInputHandler, MidiPort, Builder}; -use crate::config::{Config,DeviceConfig}; +use crate::config::{Config, DeviceConfig}; use crate::eventmap::EventMap; use crate::midi::builder::builder; +use crate::midi::{Builder, MidiInputHandler, MidiPort, PortFilter}; +use crate::util::InternalTryFrom; +use crate::{constant, Error}; -type DeviceRunItem<'a> = (&'a DeviceConfig, EventMap<'a>, Option>>); -type DeviceRunResult<'a> =(thread::ScopedJoinHandle<'a, Result<(), Error>>, mpsc::Sender); +type DeviceRunItem<'a> = ( + &'a DeviceConfig, + EventMap<'a>, + Option>>, +); +type DeviceRunResult<'a> = ( + thread::ScopedJoinHandle<'a, Result<(), Error>>, + mpsc::Sender, +); pub fn cross_shell(cmd: &str) -> Vec { if cfg!(target_os = "windows") { - vec!("cmd", "/C", cmd) + vec!["cmd", "/C", cmd] } else { - vec!("sh", "-c", cmd) + vec!["sh", "-c", cmd] } - .iter().map( - |x| x.to_string() - ).collect() + .iter() + .map(|x| x.to_string()) + .collect() } builder!(ListDevicesBuilder, list_devices, (), Result<(), Error>); @@ -31,8 +38,8 @@ builder!(RunConfigBuilder, run_config, &Config, Result<(), Error>); pub fn list_devices(input: &T, _: ()) -> Result<(), Error> where - T: MidiInputHandler+Send+'static, - ::DeviceAddr: 'static+std::fmt::Display, + T: MidiInputHandler + Send + 'static, + ::DeviceAddr: 'static + std::fmt::Display, { let ports = MidiInputHandler::ports(input)?; println!(" Addr\t Name"); @@ -44,17 +51,23 @@ where pub fn run_config(input: &T, conf: &Config) -> Result<(), Error> where - T: MidiInputHandler+Send+'static, - ::DeviceAddr: 'static+std::fmt::Display+InternalTryFrom, + T: MidiInputHandler + Send + 'static, + ::DeviceAddr: 'static + std::fmt::Display + InternalTryFrom, { - let cfevmap: Vec = conf.devices.iter().map(|x| - (x, EventMap::from(x), - x.max_connections.map(|v| (Arc::new(Mutex::new((0,v))))) - ) - ).collect(); + let cfevmap: Vec = conf + .devices + .iter() + .map(|x| { + ( + x, + EventMap::from(x), + x.max_connections.map(|v| (Arc::new(Mutex::new((0, v))))), + ) + }) + .collect(); - let (tdev,rdev) = mpsc::channel::>>(); - let (tsd,rsd) = mpsc::channel::(); + let (tdev, rdev) = mpsc::channel::>>(); + let (tsd, rsd) = mpsc::channel::(); let ntsd = tsd.clone(); let ntdev = tdev.clone(); @@ -77,12 +90,14 @@ where let mut threads: Vec = Vec::new(); let ports = input.ports()?; for p in ports { - if let Some(v) = try_connect_process(input, s, &p, &cfevmap)? { threads.push(v) } + if let Some(v) = try_connect_process(input, s, &p, &cfevmap)? { + threads.push(v) + } } let event_thread = s.spawn(move || { let mut input = T::new(constant::CLIENT_NAME_EVENT).unwrap(); - let r = input.device_events(tdev.clone(), (tsd,rsd)); + let r = input.device_events(tdev.clone(), (tsd, rsd)); tdev.send(None).unwrap(); r }); @@ -96,12 +111,17 @@ where if conf.log { println!("{}: device connect: {}", constant::CLIENT_NAME, p); } - if let Some(v) = try_connect_process(input, s, &p, &cfevmap)? { threads.push(v) } - }; + if let Some(v) = try_connect_process(input, s, &p, &cfevmap)? { + threads.push(v) + } + } event_thread.join().unwrap()?; - for (thread,ss) in threads { + for (thread, ss) in threads { let _ = ss.send(true); - let _ = thread.join().unwrap().map_err(|e| eprintln!("WARN: error in thread: {}", e)); + let _ = thread + .join() + .unwrap() + .map_err(|e| eprintln!("WARN: error in thread: {}", e)); } Ok(()) })?; @@ -112,12 +132,11 @@ fn try_connect_process<'a, T>( input: &T, s: &'a thread::Scope<'a, '_>, p: &MidiPort, - cfevmap: &'a[DeviceRunItem<'a>], - ) - -> Result>, Error> + cfevmap: &'a [DeviceRunItem<'a>], +) -> Result>, Error> where - T: MidiInputHandler+Send+'static, - ::DeviceAddr: 'static+InternalTryFrom, + T: MidiInputHandler + Send + 'static, + ::DeviceAddr: 'static + InternalTryFrom, { for (dev, eventmap, counter) in cfevmap { // device counter is full @@ -135,13 +154,13 @@ where m.0 += 1; } // stop signal channel - let (sts,srs) = mpsc::channel::(); + let (sts, srs) = mpsc::channel::(); let mm = counter.as_ref().map(Arc::clone); let nsts = sts.clone(); - let t = s.spawn( move || -> Result<(), Error> { + let t = s.spawn(move || -> Result<(), Error> { dev.run_connect()?; // blocking process - c.run(dev, eventmap, (nsts,srs))?; + c.run(dev, eventmap, (nsts, srs))?; // decrease device counter if let Some(m) = mm { let mut m = m.lock().unwrap(); diff --git a/src/util/mod.rs b/src/util/mod.rs index 1eeb686..9344ab6 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,13 +1,11 @@ - -pub mod smartset; pub mod range; pub mod remap; +pub mod smartset; pub type SmartSet = smartset::SmartSet; pub type Range = range::Range; pub type Remapper = remap::Remapper; - macro_rules! visit_from { ( $obj:ident , $( ($fct:ident, $type:ty) ),+ $(,)?) => { $( @@ -23,21 +21,25 @@ macro_rules! visit_from { pub(crate) use visit_from; -pub fn map_tryfrom(v: Vec) -> Result, >::Error> +pub fn map_tryfrom(v: Vec) -> Result, >::Error> where D: TryFrom, { - v.into_iter().map(|x| D::try_from(x)).collect::, >::Error>>() + v.into_iter() + .map(|x| D::try_from(x)) + .collect::, >::Error>>() } -pub fn map_opt_tryfrom(v: Option>) -> Result>, >::Error> +pub fn map_opt_tryfrom(v: Option>) -> Result>, >::Error> where D: TryFrom, { match v { - Some(v) => { - Ok( Some(v.into_iter().map(|x| D::try_from(x)).collect::, >::Error>>()?) ) - } + Some(v) => Ok(Some( + v.into_iter() + .map(|x| D::try_from(x)) + .collect::, >::Error>>()?, + )), None => Ok(None), } } diff --git a/src/util/range.rs b/src/util/range.rs index 62c7cfe..4db4740 100644 --- a/src/util/range.rs +++ b/src/util/range.rs @@ -1,36 +1,34 @@ -use std::str::FromStr; use std::cmp::PartialOrd; +use std::str::FromStr; -use num::{Num,NumCast}; +use num::{Num, NumCast}; use super::visit_from; // Trait aliases are unstable //trait smartsetnum = T: Num+Copy + FromStr; -#[derive(Debug,Clone,Copy)] +#[derive(Debug, Clone, Copy)] pub struct Range where - T: Num+Copy + FromStr + PartialOrd, + T: Num + Copy + FromStr + PartialOrd, { start: T, end: T, } - pub fn parse_range(s: &str) -> Result, ::Err> where -T: Num+Copy + FromStr + PartialOrd, + T: Num + Copy + FromStr + PartialOrd, { let mut osep = s.find(':'); if osep.is_none() { osep = s.find('-'); } let r = if let Some(sep) = osep { - let (p1,p2) = (&s[..sep], &s[sep+1..] ); - ( p1.parse()?, p2.parse()? ) - } - else { + let (p1, p2) = (&s[..sep], &s[sep + 1..]); + (p1.parse()?, p2.parse()?) + } else { let n = s.parse()?; (n, n) }; @@ -39,13 +37,10 @@ T: Num+Copy + FromStr + PartialOrd, impl Range where -T: Num+Copy + FromStr + PartialOrd, + T: Num + Copy + FromStr + PartialOrd, { pub fn new(start: T, end: T) -> Self { - Self { - start, - end, - } + Self { start, end } } pub fn start(&self) -> T { @@ -57,10 +52,10 @@ T: Num+Copy + FromStr + PartialOrd, } } -impl From for Range +impl From for Range where - T: Num+Copy+NumCast + FromStr + PartialOrd, - U: Num+Copy+num::ToPrimitive + FromStr, + T: Num + Copy + NumCast + FromStr + PartialOrd, + U: Num + Copy + num::ToPrimitive + FromStr, { fn from(i: U) -> Self { let ti: T = num::NumCast::from(i).unwrap(); @@ -70,7 +65,7 @@ where impl FromStr for Range where - T: Num+Copy + FromStr + PartialOrd, + T: Num + Copy + FromStr + PartialOrd, { type Err = ::Err; @@ -79,32 +74,31 @@ where } } -use std::marker::PhantomData; +use serde::de::{self, Deserialize, Deserializer, Visitor}; use std::fmt; -use serde::de::{self,Deserialize, Deserializer, Visitor}; +use std::marker::PhantomData; struct RangeVisitor where - T: Num+Copy + FromStr + PartialOrd, + T: Num + Copy + FromStr + PartialOrd, { - marker: PhantomData Range> + marker: PhantomData Range>, } - impl RangeVisitor where - T: Num+Copy + FromStr + PartialOrd, + T: Num + Copy + FromStr + PartialOrd, { fn new() -> Self { Self { - marker: PhantomData + marker: PhantomData, } } } impl<'de, T> Visitor<'de> for RangeVisitor where - T: Num+Copy+PartialOrd + FromStr +NumCast + Deserialize<'de> + std::fmt::Debug, + T: Num + Copy + PartialOrd + FromStr + NumCast + Deserialize<'de> + std::fmt::Debug, ::Err: std::fmt::Display, { type Value = Range; @@ -113,7 +107,7 @@ where formatter.write_str("a set of integer") } - visit_from!{ Range , + visit_from! { Range , (visit_i8, i8), (visit_i16, i16), (visit_i32, i32), @@ -135,7 +129,7 @@ where // This is the trait that informs Serde how to deserialize MyMap. impl<'de, T> Deserialize<'de> for Range where - T: Num+Copy+NumCast+PartialOrd + Deserialize<'de> + FromStr + std::fmt::Debug, + T: Num + Copy + NumCast + PartialOrd + Deserialize<'de> + FromStr + std::fmt::Debug, ::Err: std::fmt::Display, { fn deserialize(deserializer: D) -> Result diff --git a/src/util/remap.rs b/src/util/remap.rs index 8733903..eb7b747 100644 --- a/src/util/remap.rs +++ b/src/util/remap.rs @@ -1,17 +1,25 @@ - -use num::{Num,NumCast,ToPrimitive, Bounded}; -use std::str::FromStr; +use num::{Bounded, Num, NumCast, ToPrimitive}; use std::ops; +use std::str::FromStr; use super::Range; // Trait aliases are unstable //trait remapnum = T: Num+ToPrimitive+Copy+PartialOrd + FromStr + ops::Add + ops::Sub + ops::Div + ops::Mul; -#[derive(Debug,Clone)] +#[derive(Debug, Clone)] pub struct Remapper where - T: Num+ToPrimitive+Copy+PartialOrd+NumCast + FromStr + ops::Add + ops::Sub + ops::Div + ops::Mul, + T: Num + + ToPrimitive + + Copy + + PartialOrd + + NumCast + + FromStr + + ops::Add + + ops::Sub + + ops::Div + + ops::Mul, { src: Range, dst: Range, @@ -19,9 +27,18 @@ where impl Remapper where - T: Num+ToPrimitive+Copy+PartialOrd+NumCast + FromStr + ops::Add + ops::Sub + ops::Div + ops::Mul + std::fmt::Debug, + T: Num + + ToPrimitive + + Copy + + PartialOrd + + NumCast + + FromStr + + ops::Add + + ops::Sub + + ops::Div + + ops::Mul + + std::fmt::Debug, { - pub fn src(&self) -> &Range { &self.src } @@ -31,17 +48,13 @@ where } pub fn new(src: Range, dst: Range) -> Self { - Self { - src, - dst, - } + Self { src, dst } } - pub fn remap(&self, v: T) -> T - { + pub fn remap(&self, v: T) -> T { // compute actual value in source type - let r: T = (v-self.src.start())*(self.dst.end()-self.dst.start()) - / (self.src.end()-self.src.start()) + let r: T = (v - self.src.start()) * (self.dst.end() - self.dst.start()) + / (self.src.end() - self.src.start()) + self.dst.start(); r } @@ -49,30 +62,39 @@ where impl Remapper where - T: Num+ToPrimitive+Copy+PartialOrd+NumCast + FromStr + ops::Add + ops::Sub + ops::Div + ops::Mul + std::fmt::Debug, + T: Num + + ToPrimitive + + Copy + + PartialOrd + + NumCast + + FromStr + + ops::Add + + ops::Sub + + ops::Div + + ops::Mul + + std::fmt::Debug, { pub fn remap_to(&self, v: T) -> Option where - U: Num+NumCast+Copy+Bounded + FromStr, + U: Num + NumCast + Copy + Bounded + FromStr, { // compute actual value in source type let r: T = self.remap(v); // find min/max values of target type - let (rmin,rmax): (Option,Option) = ( + let (rmin, rmax): (Option, Option) = ( num::NumCast::from(U::min_value()), num::NumCast::from(U::max_value()), ); // if target min/max can be casted onto source, bound output to those - match (rmin,rmax) { - (Some(min),Some(max)) => { + match (rmin, rmax) { + (Some(min), Some(max)) => { if r >= max { Some(U::max_value()) } else if r <= min { Some(U::min_value()) - } - else { + } else { num::NumCast::from(r) } } diff --git a/src/util/smartset.rs b/src/util/smartset.rs index c934a5b..ff29483 100644 --- a/src/util/smartset.rs +++ b/src/util/smartset.rs @@ -1,10 +1,9 @@ - use std::collections::BTreeSet; -use std::str::FromStr; use std::ops; +use std::str::FromStr; -use num::{Num,NumCast}; +use num::{Num, NumCast}; use thiserror::Error; @@ -13,9 +12,8 @@ use thiserror::Error; pub fn parse_int_set(s: &str) -> Result, ::Err> where - T: Num+Ord+Copy + std::str::FromStr + ops::AddAssign, + T: Num + Ord + Copy + std::str::FromStr + ops::AddAssign, { - let mut r: BTreeSet = BTreeSet::new(); let parts: Vec<&str> = s.split(',').collect(); for p in parts { @@ -25,11 +23,11 @@ where osep = s.find('-'); } if let Some(sep) = osep { - let (p1,p2) = (&s[..sep], &s[sep+1..] ); - let (low,high): (T,T) = ( p1.parse()?, p2.parse()? ); - let (mut low,high) = match low <= high { - true => (low,high), - false => (high,low), + let (p1, p2) = (&s[..sep], &s[sep + 1..]); + let (low, high): (T, T) = (p1.parse()?, p2.parse()?); + let (mut low, high) = match low <= high { + true => (low, high), + false => (high, low), }; r.insert(low); loop { @@ -39,8 +37,7 @@ where } low += T::one(); } - } - else { + } else { r.insert(p.parse()?); } } @@ -48,17 +45,17 @@ where Ok(r) } -#[derive(Debug,Clone)] +#[derive(Debug, Clone)] pub struct SmartSet where - T: Num+Ord+Copy + std::str::FromStr + ops::AddAssign, + T: Num + Ord + Copy + std::str::FromStr + ops::AddAssign, { - pub set: BTreeSet + pub set: BTreeSet, } impl SmartSet where - T: Num+Ord+Copy + std::str::FromStr + ops::AddAssign, + T: Num + Ord + Copy + std::str::FromStr + ops::AddAssign, { pub fn new() -> Self { Self { @@ -77,7 +74,7 @@ where impl From for SmartSet where - T: Num+Ord+Copy+NumCast + std::str::FromStr + ops::AddAssign, + T: Num + Ord + Copy + NumCast + std::str::FromStr + ops::AddAssign, { fn from(i: T) -> Self { SmartSet { @@ -86,20 +83,20 @@ where } } -#[derive(Error,Debug)] +#[derive(Error, Debug)] pub enum Error where T: std::fmt::Display, { #[error("invalid type: `{0}`, expected {1}")] - Cast(T,String), + Cast(T, String), #[error("unknown error")] Unknown, } trait InternalTryFrom where - Self: Sized + Self: Sized, { type Error; fn i_try_from(other: T) -> Result; @@ -107,19 +104,17 @@ where impl InternalTryFrom for SmartSet where - T: Num+Ord+Copy+NumCast + std::str::FromStr + ops::AddAssign, - U: Num+Ord+Copy+num::ToPrimitive + std::str::FromStr + ops::AddAssign + std::fmt::Display, + T: Num + Ord + Copy + NumCast + std::str::FromStr + ops::AddAssign, + U: Num + Ord + Copy + num::ToPrimitive + std::str::FromStr + ops::AddAssign + std::fmt::Display, { type Error = Error; fn i_try_from(i: U) -> Result { // let mut r = SmartSet::::new(); match num::NumCast::from(i) { - Some(v) => { - Ok(SmartSet { - set: BTreeSet::from([v]), - }) - } - _ => Err(Error::Cast(i, std::any::type_name::().to_string())) + Some(v) => Ok(SmartSet { + set: BTreeSet::from([v]), + }), + _ => Err(Error::Cast(i, std::any::type_name::().to_string())), } } } @@ -141,7 +136,7 @@ where impl FromStr for SmartSet where - T: Num+Ord+Copy + std::str::FromStr + ops::AddAssign, + T: Num + Ord + Copy + std::str::FromStr + ops::AddAssign, { type Err = ::Err; @@ -154,7 +149,7 @@ where impl IntoIterator for SmartSet where - T: Num+Ord+Copy + std::str::FromStr + ops::AddAssign, + T: Num + Ord + Copy + std::str::FromStr + ops::AddAssign, { type Item = T; type IntoIter = std::collections::btree_set::IntoIter; @@ -166,7 +161,7 @@ where impl<'a, T> IntoIterator for &'a SmartSet where - T: Num+Ord+Copy + std::str::FromStr + ops::AddAssign, + T: Num + Ord + Copy + std::str::FromStr + ops::AddAssign, { type Item = &'a T; type IntoIter = std::collections::btree_set::Iter<'a, T>; @@ -176,25 +171,24 @@ where } } -use std::marker::PhantomData; +use serde::de::{self, Deserialize, Deserializer, Visitor}; use std::fmt; -use serde::de::{self,Deserialize, Deserializer, Visitor}; +use std::marker::PhantomData; struct SmartSetVisitor where - T: Num+Ord+Copy + std::str::FromStr + ops::AddAssign, + T: Num + Ord + Copy + std::str::FromStr + ops::AddAssign, { - marker: PhantomData SmartSet> + marker: PhantomData SmartSet>, } - impl SmartSetVisitor where - T: Num+Ord+Copy + std::str::FromStr + ops::AddAssign, + T: Num + Ord + Copy + std::str::FromStr + ops::AddAssign, { fn new() -> Self { Self { - marker: PhantomData + marker: PhantomData, } } } @@ -214,7 +208,14 @@ macro_rules! visit_from { impl<'de, T> Visitor<'de> for SmartSetVisitor where - T: Num+Ord+Copy+NumCast + Deserialize<'de> + std::str::FromStr + ops::AddAssign + std::fmt::Debug, + T: Num + + Ord + + Copy + + NumCast + + Deserialize<'de> + + std::str::FromStr + + ops::AddAssign + + std::fmt::Debug, ::Err: std::fmt::Display, { type Value = SmartSet; @@ -223,7 +224,7 @@ where formatter.write_str("a set of integer") } - visit_from!{ + visit_from! { (visit_i8, i8), (visit_i16, i16), (visit_i32, i32), @@ -250,12 +251,14 @@ where loop { if let Ok(Some(value)) = seq.next_element::() { - r.set.extend(&SmartSet::::from_str(&value).map_err(serde::de::Error::custom)?.set); - } - else if let Some(value) = seq.next_element()? { + r.set.extend( + &SmartSet::::from_str(&value) + .map_err(serde::de::Error::custom)? + .set, + ); + } else if let Some(value) = seq.next_element()? { r.set.insert(value); - } - else { + } else { break; } } @@ -267,7 +270,14 @@ where // This is the trait that informs Serde how to deserialize MyMap. impl<'de, T> Deserialize<'de> for SmartSet where - T: Num+Ord+Copy+NumCast + Deserialize<'de> + std::str::FromStr + ops::AddAssign + std::fmt::Debug, + T: Num + + Ord + + Copy + + NumCast + + Deserialize<'de> + + std::str::FromStr + + ops::AddAssign + + std::fmt::Debug, ::Err: std::fmt::Display, { fn deserialize(deserializer: D) -> Result