chore: apply format

This commit is contained in:
zawz 2024-12-30 16:10:30 +01:00
parent 819ef4db28
commit 0a6e237049
28 changed files with 705 additions and 510 deletions

View file

@ -1,13 +1,13 @@
log_devices: true log_devices: true
devices: devices:
- name: 'VMPK' - name: "VMPK"
max_connections: 1 max_connections: 1
queue_length: 3 queue_length: 3
interval: 100ms interval: 100ms
connect: connect:
- args: [ "sh", "-c", "echo Hello world!" ] - args: ["sh", "-c", "echo Hello world!"]
disconnect: disconnect:
- args: [ "sh", "-c", "echo Bye!" ] - args: ["sh", "-c", "echo Bye!"]
events: events:
- type: ProgramChange - type: ProgramChange
run: run:
@ -38,28 +38,28 @@ devices:
- cmd: "echo [$channel] PitchBend $value $raw $toto" - cmd: "echo [$channel] PitchBend $value $raw $toto"
envconf: envconf:
timestamp: toto timestamp: toto
- name: 'VMPK' - name: "VMPK"
log_events: true log_events: true
max_connections: 1 max_connections: 1
connect: connect:
- args: [ "sh", "-c", "echo Hello world! 2" ] - args: ["sh", "-c", "echo Hello world! 2"]
disconnect: disconnect:
- args: [ "sh", "-c", "echo Bye! 2" ] - args: ["sh", "-c", "echo Bye! 2"]
events: events:
- type: NoteOff - type: NoteOff
id: 25-30 id: 25-30
run: run:
- args: [ "sh", "-c", "echo 2 [$channel] NoteOff $id" ] - args: ["sh", "-c", "echo 2 [$channel] NoteOff $id"]
- type: NoteOn - type: NoteOn
channel: 0 channel: 0
remap: -1 remap: -1
run: run:
- args: [ "sh", "-c", "echo 2 [$channel] NoteOn $id $value" ] - args: ["sh", "-c", "echo 2 [$channel] NoteOn $id $value"]
- type: PitchBend - type: PitchBend
remap: 0-100 remap: 0-100
float: true float: true
value: 0-65535 value: 0-65535
run: run:
- args: [ "sh", "-c", "echo [$channel] PitchBend $value $raw $toto" ] - args: ["sh", "-c", "echo [$channel] PitchBend $value $raw $toto"]
envconf: envconf:
timestamp: toto timestamp: toto

View file

@ -11,4 +11,3 @@ pub struct Cli {
#[clap(long, short, action)] #[clap(long, short, action)]
pub list: bool, pub list: bool,
} }

View file

@ -1,12 +1,12 @@
use std::time::Duration; use std::time::Duration;
use super::serializer::DeviceConfigSerializer;
use super::{EventConfig, RunConfig};
use crate::event::Event; use crate::event::Event;
use crate::util; use crate::util;
use crate::Error; use crate::Error;
use super::{RunConfig,EventConfig};
use super::serializer::DeviceConfigSerializer;
#[derive(Debug,Clone)] #[derive(Debug, Clone)]
pub enum Identifier { pub enum Identifier {
All, All,
Name(String), Name(String),
@ -14,7 +14,7 @@ pub enum Identifier {
Addr(String), Addr(String),
} }
#[derive(Debug,Clone)] #[derive(Debug, Clone)]
pub struct DeviceConfig { pub struct DeviceConfig {
pub identifier: Identifier, pub identifier: Identifier,
pub max_connections: Option<u32>, pub max_connections: Option<u32>,
@ -29,12 +29,16 @@ pub struct DeviceConfig {
impl DeviceConfig { impl DeviceConfig {
fn run_internal<'a, T>(&self, v: Option<T>) -> Result<Vec<std::process::ExitStatus>, Error> fn run_internal<'a, T>(&self, v: Option<T>) -> Result<Vec<std::process::ExitStatus>, Error>
where where
T: IntoIterator<Item = &'a RunConfig> T: IntoIterator<Item = &'a RunConfig>,
{ {
let mut r = Vec::new(); let mut r = Vec::new();
if let Some(ev) = v { if let Some(ev) = v {
for e in ev { 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); r.push(v);
} }
} }
@ -46,7 +50,7 @@ impl DeviceConfig {
self.run_internal(self.connect.as_ref()) self.run_internal(self.connect.as_ref())
} }
pub fn run_disconnect(&self) -> Result<Vec<std::process::ExitStatus>, Error> { pub fn run_disconnect(&self) -> Result<Vec<std::process::ExitStatus>, Error> {
self.run_internal(self.disconnect.as_ref()) self.run_internal(self.disconnect.as_ref())
} }
} }
@ -57,21 +61,33 @@ impl TryFrom<DeviceConfigSerializer> for DeviceConfig {
Ok(DeviceConfig { Ok(DeviceConfig {
identifier: { identifier: {
match (v.name, v.regex, v.addr) { match (v.name, v.regex, v.addr) {
(Some(_), Some(_), _ ) => return Err(Error::IncompatibleArgs("name","regex")), (Some(_), Some(_), Some(_)) => {
(Some(_), None , Some(_)) => return Err(Error::IncompatibleArgs("name","addr")), return Err(Error::IncompatibleArgs("name", "regex"))
(None , Some(_), Some(_)) => return Err(Error::IncompatibleArgs("regex","addr")), }
(Some(n), None, None ) => Identifier::Name(n), (Some(_), Some(_), None) => {
(None, Some(r), None ) => Identifier::Regex(regex::Regex::new(&r)?), return Err(Error::IncompatibleArgs("name", "regex"))
(None, None , Some(a)) => Identifier::Addr(a), }
(None, None, None ) => Identifier::All, (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, 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)?, 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), 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), log: v.log_events.unwrap_or(false),
}) })
} }

View file

@ -1,6 +1,6 @@
use super::RunConfig; use super::RunConfig;
use crate::event::{Event,EventType}; use crate::event::{Event, EventType};
use crate::util::{self, SmartSet, Range, Remapper}; use crate::util::{self, Range, Remapper, SmartSet};
use super::serializer::EventConfigSerializer; use super::serializer::EventConfigSerializer;
@ -32,7 +32,7 @@ lazy_static! {
}; };
} }
#[derive(Debug,Clone)] #[derive(Debug, Clone)]
pub struct EventConfig { pub struct EventConfig {
pub run: Vec<RunConfig>, pub run: Vec<RunConfig>,
pub r#type: EventType, pub r#type: EventType,
@ -46,7 +46,7 @@ pub struct EventConfig {
impl EventConfig { impl EventConfig {
pub fn match_value(&self, event: &Event) -> bool { pub fn match_value(&self, event: &Event) -> bool {
match &self.value { match &self.value {
Some(v) => v.set.contains(&event.value), Some(v) => v.set.contains(&event.value),
None => true, None => true,
} }
} }
@ -59,21 +59,30 @@ impl TryFrom<EventConfigSerializer> for EventConfig {
run: util::map_tryfrom(v.run)?, run: util::map_tryfrom(v.run)?,
r#type: v.r#type, r#type: v.r#type,
channel: match v.r#type.has_channel() { 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(), false => NULL_DEFAULT_MAP.clone(),
}, },
id: match v.r#type.has_id() { 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(), 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), float: v.float.unwrap_or(false),
value: v.value, value: v.value,
}; };
if let Some(remap) = &r.remap { if let Some(remap) = &r.remap {
let range = remap.src(); let range = remap.src();
if range.start() < i64::MIN as f64 { return Err(Self::Error::RemapTooLow(range.start())) } if range.start() < i64::MIN as f64 {
if range.end() > i64::MAX as f64 { return Err(Self::Error::RemapTooBig(range.end())) } return Err(Self::Error::RemapTooLow(range.start()));
}
if range.end() > i64::MAX as f64 {
return Err(Self::Error::RemapTooBig(range.end()));
}
} }
Ok(r) Ok(r)
} }

View file

@ -1,5 +1,5 @@
pub mod event;
pub mod device; pub mod device;
pub mod event;
pub mod run; pub mod run;
pub mod serializer; pub mod serializer;
@ -14,7 +14,7 @@ pub use event::EventConfig;
pub use run::RunConfig; pub use run::RunConfig;
pub type EventEnvMap = serializer::EventEnvSerializer; pub type EventEnvMap = serializer::EventEnvSerializer;
#[derive(Clone,Debug)] #[derive(Clone, Debug)]
pub struct Config { pub struct Config {
pub log: bool, pub log: bool,
pub driver: Option<crate::midi::MidiDriver>, pub driver: Option<crate::midi::MidiDriver>,

View file

@ -4,7 +4,7 @@ use std::process::{Command, ExitStatus};
use super::serializer::RunConfigSerializer; use super::serializer::RunConfigSerializer;
use super::EventEnvMap; use super::EventEnvMap;
#[derive(Debug,Clone)] #[derive(Debug, Clone)]
pub struct RunConfig { pub struct RunConfig {
pub args: Vec<String>, pub args: Vec<String>,
pub envconf: Option<EventEnvMap>, pub envconf: Option<EventEnvMap>,
@ -19,9 +19,7 @@ impl RunConfig {
} }
c.envs(env); c.envs(env);
if self.detach { if self.detach {
std::thread::spawn(move || { std::thread::spawn(move || c.status());
c.status()
});
Ok(None) Ok(None)
} else { } else {
c.status().map(|v| Some(v)) c.status().map(|v| Some(v))
@ -34,19 +32,17 @@ impl TryFrom<RunConfigSerializer> for RunConfig {
fn try_from(v: RunConfigSerializer) -> Result<Self, Self::Error> { fn try_from(v: RunConfigSerializer) -> Result<Self, Self::Error> {
let args = if v.args.is_some() { let args = if v.args.is_some() {
v.args.unwrap() v.args.unwrap()
} } else if v.cmd.is_some() {
else if v.cmd.is_some() {
crate::run::cross_shell(v.cmd.as_ref().unwrap()) crate::run::cross_shell(v.cmd.as_ref().unwrap())
} } else {
else { return Err(crate::Error::from(
return Err(crate::Error::from(crate::error::ConfigError::RunMissingArgs)); crate::error::ConfigError::RunMissingArgs,
));
}; };
Ok( Ok(RunConfig {
RunConfig { args,
args, envconf: v.envconf,
envconf: v.envconf, detach: v.detach.unwrap_or(false),
detach: v.detach.unwrap_or(false), })
}
)
} }
} }

View file

@ -1,11 +1,11 @@
use std::time::Duration; use std::time::Duration;
use super::{RunConfigSerializer,EventConfigSerializer}; use super::{EventConfigSerializer, RunConfigSerializer};
use duration_str::deserialize_duration; use duration_str::deserialize_duration;
use serde::Deserialize; use serde::Deserialize;
#[derive(Debug,Clone,Deserialize)] #[derive(Debug, Clone, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
pub enum DurationWrapper { pub enum DurationWrapper {
#[serde(deserialize_with = "deserialize_duration")] #[serde(deserialize_with = "deserialize_duration")]
@ -13,15 +13,14 @@ pub enum DurationWrapper {
} }
impl DurationWrapper { impl DurationWrapper {
pub fn unwrap(self) -> Duration pub fn unwrap(self) -> Duration {
{
match self { match self {
DurationWrapper::Some(v) => v, DurationWrapper::Some(v) => v,
} }
} }
} }
#[derive(Deserialize,Debug,Clone)] #[derive(Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct DeviceConfigSerializer { pub struct DeviceConfigSerializer {
pub name: Option<String>, pub name: Option<String>,

View file

@ -1,10 +1,10 @@
use super::RunConfigSerializer; use super::RunConfigSerializer;
use crate::event::EventType; use crate::event::EventType;
use crate::util::{SmartSet,Range}; use crate::util::{Range, SmartSet};
use serde::Deserialize; use serde::Deserialize;
#[derive(Deserialize,Debug,Clone)] #[derive(Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct EventConfigSerializer { pub struct EventConfigSerializer {
pub run: Vec<RunConfigSerializer>, pub run: Vec<RunConfigSerializer>,

View file

@ -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)] #[serde(deny_unknown_fields)]
pub struct EventEnvSerializer { pub struct EventEnvSerializer {
pub channel: Option<String>, pub channel: Option<String>,
@ -10,4 +9,4 @@ pub struct EventEnvSerializer {
pub rawvalue: Option<String>, pub rawvalue: Option<String>,
pub timestamp: Option<String>, pub timestamp: Option<String>,
pub value: Option<String>, pub value: Option<String>,
} }

View file

@ -1,16 +1,16 @@
pub mod event;
pub mod device; pub mod device;
pub mod run; pub mod event;
pub mod eventenv; pub mod eventenv;
pub mod run;
pub use device::DeviceConfigSerializer; pub use device::DeviceConfigSerializer;
pub use event::EventConfigSerializer; pub use event::EventConfigSerializer;
pub use run::RunConfigSerializer;
pub use eventenv::EventEnvSerializer; pub use eventenv::EventEnvSerializer;
pub use run::RunConfigSerializer;
use serde::Deserialize; use serde::Deserialize;
#[derive(Deserialize,Clone,Debug)] #[derive(Deserialize, Clone, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct ConfigSerializer { pub struct ConfigSerializer {
pub log_devices: Option<bool>, pub log_devices: Option<bool>,

View file

@ -1,12 +1,12 @@
use super::EventEnvSerializer; 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)] #[serde(deny_unknown_fields)]
pub struct RunConfigSerializer { pub struct RunConfigSerializer {
pub args: Option<Vec<String>>, pub args: Option<Vec<String>>,
pub cmd: Option<String>, pub cmd: Option<String>,
pub envconf: Option<EventEnvSerializer>, pub envconf: Option<EventEnvSerializer>,
pub detach: Option<bool>, pub detach: Option<bool>,
} }

View file

@ -1,4 +1,3 @@
pub const CLIENT_NAME: &str = "rmidimap"; pub const CLIENT_NAME: &str = "rmidimap";
pub const CLIENT_NAME_HANDLER: &str = "rmidimap-handler"; pub const CLIENT_NAME_HANDLER: &str = "rmidimap-handler";
pub const CLIENT_NAME_EVENT: &str = "rmidimap-event-watcher"; pub const CLIENT_NAME_EVENT: &str = "rmidimap-event-watcher";

View file

@ -8,7 +8,7 @@ use crate::midi::backend::alsa::AlsaError;
use thiserror::Error; use thiserror::Error;
#[derive(Error,Debug)] #[derive(Error, Debug)]
pub enum Error { pub enum Error {
#[error(transparent)] #[error(transparent)]
IO(#[from] std::io::Error), IO(#[from] std::io::Error),
@ -44,7 +44,7 @@ pub enum Error {
Unknown, Unknown,
} }
#[derive(Error,Debug)] #[derive(Error, Debug)]
pub enum ConfigError { pub enum ConfigError {
#[error("run config is missing execution configuration, either \"args\" or \"cmd\" has to be specified")] #[error("run config is missing execution configuration, either \"args\" or \"cmd\" has to be specified")]
RunMissingArgs, RunMissingArgs,

View file

@ -1,11 +1,11 @@
use std::fmt::{Display, Write};
use std::{collections::HashMap, time::SystemTime}; use std::{collections::HashMap, time::SystemTime};
use std::fmt::{Write,Display};
use crate::config::EventEnvMap; use crate::config::EventEnvMap;
use crate::util::Remapper; use crate::util::Remapper;
use crate::Error; use crate::Error;
use serde::{Serialize,Deserialize}; use serde::{Deserialize, Serialize};
use lazy_static::lazy_static; use lazy_static::lazy_static;
@ -21,11 +21,12 @@ lazy_static! {
} }
pub fn event_to_key(r#type: EventType, channel: u8, id: u8) -> u32 { 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)] #[repr(u8)]
#[derive(Serialize,Deserialize,Debug,Copy,Clone,Default,Display)] #[derive(Serialize, Deserialize, Debug, Copy, Clone, Default, enum_display_derive::Display)]
pub enum EventType { pub enum EventType {
#[default] #[default]
Unknown = 0b0000, Unknown = 0b0000,
@ -41,42 +42,36 @@ pub enum EventType {
impl EventType { impl EventType {
pub fn has_id(&self) -> bool { 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 { pub fn has_channel(&self) -> bool {
!matches!(self, EventType::Unknown | EventType::System ) !matches!(self, EventType::Unknown | EventType::System)
} }
pub fn min_value(&self) -> i32 { pub fn min_value(&self) -> i32 {
match self { match self {
EventType::NoteOff | EventType::NoteOff | EventType::NoteOn | EventType::Controller => 0,
EventType::NoteOn | EventType::PolyphonicKeyPressure | EventType::ChannelPressure => 127,
EventType::Controller EventType::PitchBend => 0,
=> 0,
EventType::PolyphonicKeyPressure |
EventType::ChannelPressure
=> 127,
EventType::PitchBend
=> 0,
_ => 0, _ => 0,
} }
} }
pub fn max_value(&self) -> i32 { pub fn max_value(&self) -> i32 {
match self { match self {
EventType::NoteOff | EventType::NoteOff | EventType::NoteOn | EventType::Controller => 127,
EventType::NoteOn | EventType::PolyphonicKeyPressure | EventType::ChannelPressure => 127,
EventType::Controller EventType::PitchBend => 32767,
=> 127,
EventType::PolyphonicKeyPressure |
EventType::ChannelPressure
=> 127,
EventType::PitchBend
=> 32767,
_ => 0, _ => 0,
} }
} }
} }
#[derive(Debug,Default)] #[derive(Debug, Default)]
pub struct Event<'a> { pub struct Event<'a> {
pub r#type: EventType, pub r#type: EventType,
pub channel: u8, pub channel: u8,
@ -86,7 +81,7 @@ pub struct Event<'a> {
pub timestamp: Option<SystemTime>, pub timestamp: Option<SystemTime>,
} }
#[derive(Debug,Clone,Default)] #[derive(Debug, Clone, Default)]
pub struct EventBuf { pub struct EventBuf {
pub r#type: EventType, pub r#type: EventType,
pub channel: u8, pub channel: u8,
@ -105,7 +100,7 @@ pub struct EventEnv {
pub value: String, pub value: String,
} }
#[derive(Clone,Debug)] #[derive(Clone, Debug)]
struct EventEnvRef<'a> { struct EventEnvRef<'a> {
pub channel: &'a str, pub channel: &'a str,
pub id: &'a str, pub id: &'a str,
@ -115,11 +110,17 @@ struct EventEnvRef<'a> {
pub value: &'a str, pub value: &'a str,
} }
impl<'a> std::fmt::Display for Event<'a> { impl<'a> std::fmt::Display for Event<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{{ \"type\": \"{}\", \"channel\": {}, \"id\": {}, \"value\": {}, \"raw\": \"{}\" }}", write!(
self.r#type, self.channel, self.id, self.value, bytes_to_strhex(self.raw, " ")) 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<EventBuf> for Event<'_> {
impl From<u8> for EventType { impl From<u8> for EventType {
fn from(v: u8) -> Self { fn from(v: u8) -> Self {
if ! (0b1000..=0b1111).contains(&v) { if !(0b1000..=0b1111).contains(&v) {
// not in defined space: unknown // not in defined space: unknown
EventType::Unknown EventType::Unknown
} } else {
else {
// safe since all valid cases are defined // safe since all valid cases are defined
unsafe { std::mem::transmute(v) } unsafe { std::mem::transmute(v) }
} }
@ -195,19 +195,23 @@ impl<'a> Event<'a> {
event_to_key(self.r#type, self.channel, self.id) event_to_key(self.r#type, self.channel, self.id)
} }
pub fn make_env(&self, remap: Option<&Remapper<f64>>, float: bool) -> Result<EventEnv, Error> pub fn make_env(&self, remap: Option<&Remapper<f64>>, float: bool) -> Result<EventEnv, Error> {
{
Ok(EventEnv { Ok(EventEnv {
channel: self.channel.to_string(), channel: self.channel.to_string(),
id: self.id.to_string(), id: self.id.to_string(),
rawvalue: self.value.to_string(), rawvalue: self.value.to_string(),
raw: bytes_to_strhex(self.raw, " "), raw: bytes_to_strhex(self.raw, " "),
timestamp: self.timestamp.unwrap_or(SystemTime::now()).duration_since(SystemTime::UNIX_EPOCH)?.as_secs_f64().to_string(), timestamp: self
value: match (remap,float) { .timestamp
(Some(r),true) => r.remap(self.value as f64).to_string(), .unwrap_or(SystemTime::now())
(Some(r),false) => r.remap_to::<i64>(self.value as f64).unwrap().to_string(), .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::<i64>(self.value as f64).unwrap().to_string(),
_ => self.value.to_string(), _ => self.value.to_string(),
} },
}) })
} }
} }
@ -218,20 +222,25 @@ impl<'a> From<&'a [u8]> for Event<'a> {
eprintln!("warning: empty signal"); eprintln!("warning: empty signal");
return Default::default(); return Default::default();
} }
let event_type = EventType::from(v[0]/16); let event_type = EventType::from(v[0] / 16);
let channel = if event_type.has_channel() { v[0]%16 } else { 0 }; let channel = if event_type.has_channel() {
v[0] % 16
} else {
0
};
let (id, value) = match event_type { let (id, value) = match event_type {
EventType::PitchBend => { EventType::PitchBend => (0, (v[2] as u16) * 256 + (v[1] as u16)),
(0, (v[2] as u16)*256 + (v[1] as u16) )
},
EventType::Unknown => { EventType::Unknown => {
eprintln!("warning: unknown signal type: {}", v[0]); eprintln!("warning: unknown signal type: {}", v[0]);
(0,0) (0, 0)
} }
EventType::System => (0,0), EventType::System => (0, 0),
EventType::ChannelPressure => (0,v[1] as u16), EventType::ChannelPressure => (0, v[1] as u16),
EventType::ProgramChange => (v[1],0), EventType::ProgramChange => (v[1], 0),
EventType::NoteOn | EventType::NoteOff | EventType::PolyphonicKeyPressure | EventType::Controller => (v[1],(v[2] as u16)), EventType::NoteOn
| EventType::NoteOff
| EventType::PolyphonicKeyPressure
| EventType::Controller => (v[1], (v[2] as u16)),
}; };
Event { Event {
r#type: event_type, r#type: event_type,
@ -245,19 +254,41 @@ impl<'a> From<&'a [u8]> for Event<'a> {
} }
impl EventEnv { 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 mut r = HashMap::new();
let keys: EventEnvRef = match m { let keys: EventEnvRef = match m {
Some(v) => { Some(v) => EventEnvRef {
EventEnvRef { channel: v
channel: v.channel.as_ref().map(|x| &x[..]).unwrap_or(EVENT_ENV_DEFAULT.channel), .channel
id: v.id.as_ref().map(|x| &x[..]).unwrap_or(EVENT_ENV_DEFAULT.id), .as_ref()
raw: v.raw.as_ref().map(|x| &x[..]).unwrap_or(EVENT_ENV_DEFAULT.raw), .map(|x| &x[..])
rawvalue: v.rawvalue.as_ref().map(|x| &x[..]).unwrap_or(EVENT_ENV_DEFAULT.rawvalue), .unwrap_or(EVENT_ENV_DEFAULT.channel),
timestamp: v.timestamp.as_ref().map(|x| &x[..]).unwrap_or(EVENT_ENV_DEFAULT.timestamp), id: v
value: v.value.as_ref().map(|x| &x[..]).unwrap_or(EVENT_ENV_DEFAULT.value), .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(), _ => EVENT_ENV_DEFAULT.clone(),
}; };
r.insert(keys.channel, self.channel); r.insert(keys.channel, self.channel);

View file

@ -1,24 +1,27 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::config::{EventConfig,DeviceConfig}; use crate::config::{DeviceConfig, EventConfig};
use crate::event::{EventType,Event}; use crate::event::{Event, EventType};
use crate::Error; use crate::Error;
#[derive(Debug,Default)] #[derive(Debug, Default)]
pub struct EventMap<'a> { pub struct EventMap<'a> {
pub map: HashMap<u32, Vec<&'a EventConfig>>, pub map: HashMap<u32, Vec<&'a EventConfig>>,
} }
fn event_to_key(r#type: EventType, channel: u8, id: u8) -> u32 { 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 { pub fn count_events(events: &[EventConfig]) -> usize {
events.iter().map(|x| { events
let nchannel = x.channel.len(); .iter()
let nid = x.id.len(); .map(|x| {
nchannel * nid let nchannel = x.channel.len();
}).sum() let nid = x.id.len();
nchannel * nid
})
.sum()
} }
impl<'a> EventMap<'a> { impl<'a> EventMap<'a> {
@ -29,8 +32,7 @@ impl<'a> EventMap<'a> {
let key = event_to_key(event.r#type, channel, id); let key = event_to_key(event.r#type, channel, id);
if let Some(v) = self.map.get_mut(&key) { if let Some(v) = self.map.get_mut(&key) {
v.push(event); v.push(event);
} } else {
else {
self.map.insert(key, Vec::from([event])); 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); let key = event_to_key(event.r#type, event.channel, event.id);
if let Some(v) = self.map.get(&key) { if let Some(v) = self.map.get(&key) {
for ev in v { for ev in v {
if ev.match_value(event) { if ev.match_value(event) {
for r in &ev.run { 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)?; r.run(env)?;
} }
} }
@ -58,12 +62,13 @@ impl<'a> From<&'a [EventConfig]> for EventMap<'a> {
fn from(events: &'a [EventConfig]) -> Self { fn from(events: &'a [EventConfig]) -> Self {
// init hashmap with size for optimizing // init hashmap with size for optimizing
let size = count_events(events); 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 // insert references
ret.add_events(events); ret.add_events(events);
ret ret
} }
} }
impl<'a> From<&'a DeviceConfig> for EventMap<'a> { 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 // init hashmap with size for optimizing
let size = count_events(device.events.as_ref().map(|x| &x[..]).unwrap_or(&[])); 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 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 // insert references
if let Some(x) = device.events.as_ref() { if let Some(x) = device.events.as_ref() {
ret.add_events(x); ret.add_events(x);
} }
ret ret
} }
} }

View file

@ -1,15 +1,12 @@
#[macro_use] pub mod cli;
extern crate enum_display_derive;
pub mod config; pub mod config;
pub mod run; pub mod constant;
pub mod error;
pub mod event; pub mod event;
pub mod eventmap; pub mod eventmap;
pub mod midi; pub mod midi;
pub mod run;
pub mod util; pub mod util;
pub mod cli;
pub mod error;
pub mod constant;
type Error = error::Error; type Error = error::Error;
@ -17,33 +14,27 @@ use std::path::Path;
use clap::Parser; use clap::Parser;
use config::Config;
use cli::Cli; use cli::Cli;
use config::Config;
use midi::MidiHandler; use midi::MidiHandler;
fn main() { fn main() {
let c = Cli::parse(); let c = Cli::parse();
if c.list { if c.list {
let mut handler = err_handle(MidiHandler::new(constant::CLIENT_NAME)); let mut handler = err_handle(MidiHandler::new(constant::CLIENT_NAME));
err_handle( err_handle(handler.builder_handler(run::ListDevicesBuilder, ()));
handler.builder_handler(run::ListDevicesBuilder, ())
);
return; return;
} }
let map_file = err_handle( let map_file = err_handle(c.map_file.ok_or(Error::NoArgument));
c.map_file.ok_or(Error::NoArgument)
);
loop { loop {
err_handle( err_handle(run_file(&map_file));
run_file(&map_file)
);
} }
} }
fn err_handle<T,E>(r: Result<T, E>) -> T fn err_handle<T, E>(r: Result<T, E>) -> T
where where
E: std::fmt::Display E: std::fmt::Display,
{ {
match r { match r {
Ok(v) => v, Ok(v) => v,
@ -56,7 +47,7 @@ where
fn run_file(filepath: &Path) -> Result<(), Error> { fn run_file(filepath: &Path) -> Result<(), Error> {
println!("Load file {}", filepath.to_str().unwrap_or("<unknown>")); println!("Load file {}", filepath.to_str().unwrap_or("<unknown>"));
let dat = std::fs::read( filepath )?; let dat = std::fs::read(filepath)?;
let conf = Config::try_from(&dat[..])?; let conf = Config::try_from(&dat[..])?;
let mut handler = match conf.driver { let mut handler = match conf.driver {
Some(v) => MidiHandler::new_with_driver(constant::CLIENT_NAME, v), Some(v) => MidiHandler::new_with_driver(constant::CLIENT_NAME, v),

View file

@ -1,21 +1,24 @@
extern crate libc;
extern crate alsa; extern crate alsa;
extern crate libc;
use std::ffi::{CStr, CString};
use std::str::FromStr; use std::str::FromStr;
use std::{mem, thread};
use std::ffi::{CString, CStr};
use std::time::SystemTime;
use std::sync::mpsc; use std::sync::mpsc;
use std::time::SystemTime;
use std::{mem, thread};
use crate::midi::{MidiInput,MidiPort,PortFilter};
use crate::error::Error; use crate::error::Error;
use crate::midi::{MidiInput, MidiPort, PortFilter};
use crate::util::InternalTryFrom; use crate::util::InternalTryFrom;
use alsa::{Seq, Direction}; use alsa::seq::{
use alsa::seq::{ClientIter, PortIter, MidiEvent, PortInfo, PortSubscribe, Addr, QueueTempo, EventType, PortCap, PortType}; Addr, ClientIter, EventType, MidiEvent, PortCap, PortInfo, PortIter, PortSubscribe, PortType,
QueueTempo,
};
use alsa::{Direction, Seq};
use thiserror::Error; use thiserror::Error;
#[derive(Debug,Clone,PartialEq,Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct DeviceAddr(Addr); pub struct DeviceAddr(Addr);
const ANNOUNCE_ADDR: &str = "System:Announce"; const ANNOUNCE_ADDR: &str = "System:Announce";
@ -39,15 +42,16 @@ impl FromStr for DeviceAddr {
// todo!() // todo!()
// let mut osep = ; // let mut osep = ;
if let Some(sep) = s.find(':') { if let Some(sep) = s.find(':') {
let (p1,p2) = (&s[..sep], &s[sep+1..] ); let (p1, p2) = (&s[..sep], &s[sep + 1..]);
Ok(DeviceAddr( Ok(DeviceAddr(Addr {
Addr { client: p1
client: p1.parse().map_err(|_| AlsaError::AddrParse(s.to_string()))?, .parse()
port: p2.parse().map_err(|_| AlsaError::AddrParse(s.to_string()))?, .map_err(|_| AlsaError::AddrParse(s.to_string()))?,
} port: p2
)) .parse()
} .map_err(|_| AlsaError::AddrParse(s.to_string()))?,
else { }))
} else {
Err(AlsaError::AddrParse(s.to_string())) Err(AlsaError::AddrParse(s.to_string()))
} }
} }
@ -72,7 +76,8 @@ impl DeviceAddr {
} }
pub fn get_ports(s: &Seq, capability: PortCap) -> Vec<PortInfo> { pub fn get_ports(s: &Seq, capability: PortCap) -> Vec<PortInfo> {
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)) .filter(|p| p.get_capability().contains(capability))
.collect() .collect()
} }
@ -83,7 +88,7 @@ mod helpers {
} }
} }
#[derive(Error,Debug)] #[derive(Error, Debug)]
pub enum AlsaError { pub enum AlsaError {
#[error(transparent)] #[error(transparent)]
ALSA(#[from] alsa::Error), ALSA(#[from] alsa::Error),
@ -99,7 +104,7 @@ pub struct MidiInputAlsa {
subscription: Option<PortSubscribe>, subscription: Option<PortSubscribe>,
connect_addr: Option<Addr>, connect_addr: Option<Addr>,
start_time: Option<SystemTime>, start_time: Option<SystemTime>,
stop_trigger: [i32;2], stop_trigger: [i32; 2],
} }
impl Drop for MidiInputAlsa { impl Drop for MidiInputAlsa {
@ -119,10 +124,11 @@ impl MidiInputAlsa {
} }
} }
fn init_queue(&mut self) -> Result<i32, alsa::Error> { fn init_queue(&mut self) -> Result<i32, alsa::Error> {
// Create the input queue // 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) // Set arbitrary tempo (mm=100) and resolution (240)
let qtempo = QueueTempo::empty()?; let qtempo = QueueTempo::empty()?;
qtempo.set_tempo(600_000); qtempo.set_tempo(600_000);
@ -130,7 +136,6 @@ impl MidiInputAlsa {
self.seq.set_queue_tempo(queue_id, &qtempo)?; self.seq.set_queue_tempo(queue_id, &qtempo)?;
let _ = self.seq.drain_output(); let _ = self.seq.drain_output();
Ok(queue_id) 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 { 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 // 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.drain_output();
let _ = self.seq.free_queue(self.queue_id); let _ = self.seq.free_queue(self.queue_id);
for fd in self.stop_trigger { for fd in self.stop_trigger {
if fd >= 0 { if fd >= 0 {
unsafe { self::libc::close(fd) }; unsafe { self::libc::close(fd) };
@ -179,16 +186,24 @@ impl MidiInputAlsa {
} }
fn signal_stop_input_internal(stop_trigger: i32) -> Result<(), Error> { 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::<bool>() as self::libc::size_t) } == -1 { if unsafe {
self::libc::write(
stop_trigger,
&false as *const bool as *const _,
mem::size_of::<bool>() as self::libc::size_t,
)
} == -1
{
Err(Error::Pipe) Err(Error::Pipe)
} } else {
else {
Ok(()) Ok(())
} }
} }
fn alsa_input_handler<F, D>(&mut self, callback: F, mut userdata: D) -> Result<(), Error> fn alsa_input_handler<F, D>(&mut self, callback: F, mut userdata: D) -> Result<(), Error>
where F: Fn(&Self, alsa::seq::Event, &mut D) -> Result<bool, Error> { where
F: Fn(&Self, alsa::seq::Event, &mut D) -> Result<bool, Error>,
{
// fd defitions // fd defitions
use self::alsa::PollDescriptors; use self::alsa::PollDescriptors;
use self::libc::pollfd; use self::libc::pollfd;
@ -202,7 +217,7 @@ impl MidiInputAlsa {
// make poll fds // make poll fds
let poll_desc_info = (&self.seq, Some(Direction::Capture)); 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 { poll_fds[0] = pollfd {
fd: self.stop_trigger[0], fd: self.stop_trigger[0],
events: self::libc::POLLIN, events: self::libc::POLLIN,
@ -217,7 +232,13 @@ impl MidiInputAlsa {
// Read stop event from triggerer // Read stop event from triggerer
if poll_fds[0].revents & self::libc::POLLIN != 0 { if poll_fds[0].revents & self::libc::POLLIN != 0 {
let mut pollread = false; 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::<bool>() 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::<bool>() as self::libc::size_t,
)
};
if !pollread { if !pollread {
break; break;
} }
@ -243,7 +264,7 @@ impl MidiInputAlsa {
Err(e) => { Err(e) => {
eprintln!("ALSA CALLBACK ERROR: {}", e); eprintln!("ALSA CALLBACK ERROR: {}", e);
eprintln!("continuing execution"); eprintln!("continuing execution");
}, }
} }
} }
Ok(()) Ok(())
@ -251,13 +272,13 @@ impl MidiInputAlsa {
fn binary_input_handler<F, D>(&mut self, callback: F, userdata: D) -> Result<(), Error> fn binary_input_handler<F, D>(&mut self, callback: F, userdata: D) -> Result<(), Error>
where where
F: Fn(&Self, Option<SystemTime>, &[u8], &mut D) -> Result<(),Error> + Send F: Fn(&Self, Option<SystemTime>, &[u8], &mut D) -> Result<(), Error> + Send,
{ {
let decoder = MidiEvent::new(0)?; let decoder = MidiEvent::new(0)?;
decoder.enable_running_status(false); decoder.enable_running_status(false);
let message = vec!(); let message = vec![];
let buffer: [u8;12] = [0;12]; let buffer: [u8; 12] = [0; 12];
let continue_sysex = false; let continue_sysex = false;
let ts = match self.start_time.as_ref() { let ts = match self.start_time.as_ref() {
@ -265,48 +286,61 @@ impl MidiInputAlsa {
_ => SystemTime::now(), _ => SystemTime::now(),
}; };
self.alsa_input_handler(|s, mut ev, (message, buffer, continue_sysex, userdata)| { self.alsa_input_handler(
if !*continue_sysex { message.clear() } |s, mut ev, (message, buffer, continue_sysex, userdata)| {
if !*continue_sysex {
let do_decode = match ev.get_type() { message.clear()
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! let do_decode = match ev.get_type() {
if do_decode { EventType::PortSubscribed
let nbytes = decoder.decode(buffer, &mut ev).map_err(|_| AlsaError::Decode)?; | EventType::PortUnsubscribed
if nbytes > 0 { | EventType::Qframe
message.extend_from_slice(&buffer[0..nbytes+1]); | 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<SystemTime> = ev.get_time().map(|v| ts+v); let ts: Option<SystemTime> = ev.get_time().map(|v| ts + v);
(callback)(s, ts, message, userdata)?; (callback)(s, ts, message, userdata)?;
Ok(false) Ok(false)
} },
, (message, buffer, continue_sysex, userdata))?; (message, buffer, continue_sysex, userdata),
)?;
Ok(()) Ok(())
} }
fn threaded_alsa_input<F, D>(&mut self, callback: F, (ts, rs): (mpsc::Sender<bool>, mpsc::Receiver<bool>), userdata: D) -> Result<(),Error> fn threaded_alsa_input<F, D>(
&mut self,
callback: F,
(ts, rs): (mpsc::Sender<bool>, mpsc::Receiver<bool>),
userdata: D,
) -> Result<(), Error>
where where
F: Fn(&Self, alsa::seq::Event, &mut D) -> Result<bool, Error> + Send, F: Fn(&Self, alsa::seq::Event, &mut D) -> Result<bool, Error> + Send,
D: Send, D: Send,
{ {
thread::scope( |sc| -> Result<(), Error> { thread::scope(|sc| -> Result<(), Error> {
let stop_trigger = self.stop_trigger[1]; let stop_trigger = self.stop_trigger[1];
let t = sc.spawn(move || -> Result<(), Error> { let t = sc.spawn(move || -> Result<(), Error> {
let userdata = userdata; let userdata = userdata;
@ -316,20 +350,26 @@ impl MidiInputAlsa {
}); });
match rs.recv()? { match rs.recv()? {
true => Self::signal_stop_input_internal(stop_trigger)?, true => Self::signal_stop_input_internal(stop_trigger)?,
false => () false => (),
}; };
t.join().expect("unexpected thread error")?; t.join().expect("unexpected thread error")?;
Ok(()) Ok(())
}) })
} }
fn threaded_handler<H, F, T, RF: ?Sized, D, R>(&mut self, handler: H, callback: F, (ts, rs): (mpsc::Sender<bool>, mpsc::Receiver<bool>), userdata: D) -> Result<(),Error> fn threaded_handler<H, F, T, RF: ?Sized, D, R>(
&mut self,
handler: H,
callback: F,
(ts, rs): (mpsc::Sender<bool>, mpsc::Receiver<bool>),
userdata: D,
) -> Result<(), Error>
where where
H: Fn(&mut Self, F,D) -> Result<(), Error> + Send, H: Fn(&mut Self, F, D) -> Result<(), Error> + Send,
F: Fn(&Self, T, &RF, &mut D) -> Result<R,Error> + Send, F: Fn(&Self, T, &RF, &mut D) -> Result<R, Error> + Send,
D: Send, D: Send,
{ {
thread::scope( |sc| -> Result<(), Error> { thread::scope(|sc| -> Result<(), Error> {
let stop_trigger = self.stop_trigger[1]; let stop_trigger = self.stop_trigger[1];
let t = sc.spawn(move || -> Result<(), Error> { let t = sc.spawn(move || -> Result<(), Error> {
let userdata = userdata; let userdata = userdata;
@ -339,7 +379,7 @@ impl MidiInputAlsa {
}); });
match rs.recv()? { match rs.recv()? {
true => Self::signal_stop_input_internal(stop_trigger)?, true => Self::signal_stop_input_internal(stop_trigger)?,
false => () false => (),
}; };
t.join().expect("unexpected thread error")?; t.join().expect("unexpected thread error")?;
Ok(()) Ok(())
@ -361,7 +401,7 @@ impl MidiInput for MidiInputAlsa {
subscription: None, subscription: None,
connect_addr: None, connect_addr: None,
start_time: None, start_time: None,
stop_trigger: [-1,-1], stop_trigger: [-1, -1],
}) })
} }
@ -371,26 +411,29 @@ impl MidiInput for MidiInputAlsa {
} }
fn ports(&self) -> Result<Vec<MidiPort<DeviceAddr>>, Error> { fn ports(&self) -> Result<Vec<MidiPort<DeviceAddr>>, Error> {
get_ports(&self.seq, PortCap::READ | PortCap::SUBS_READ).iter().map(|x| -> Result<MidiPort<DeviceAddr>, Error> { get_ports(&self.seq, PortCap::READ | PortCap::SUBS_READ)
let cinfo = self.seq.get_any_client_info(x.get_client())?; .iter()
Ok(MidiPort { .map(|x| -> Result<MidiPort<DeviceAddr>, Error> {
name: cinfo.get_name()?.to_string()+":"+x.get_name()?, let cinfo = self.seq.get_any_client_info(x.get_client())?;
addr: x.addr().into(), Ok(MidiPort {
name: cinfo.get_name()?.to_string() + ":" + x.get_name()?,
addr: x.addr().into(),
})
}) })
}).collect() .collect()
} }
fn filter_ports(&self, mut ports: Vec<MidiPort<DeviceAddr>>, filter: PortFilter<Self::DeviceAddr>) -> Vec<MidiPort<DeviceAddr>> { fn filter_ports(
ports.retain( &self,
|p| { mut ports: Vec<MidiPort<DeviceAddr>>,
match &filter { filter: PortFilter<Self::DeviceAddr>,
PortFilter::All => true, ) -> Vec<MidiPort<DeviceAddr>> {
PortFilter::Name(s) => p.name.contains(s), ports.retain(|p| match &filter {
PortFilter::Regex(s) => s.is_match(&p.name), PortFilter::All => true,
PortFilter::Addr(s) => p.addr == *s, PortFilter::Name(s) => p.name.contains(s),
} PortFilter::Regex(s) => s.is_match(&p.name),
} PortFilter::Addr(s) => p.addr == *s,
); });
ports ports
} }
@ -403,7 +446,10 @@ impl MidiInput for MidiInputAlsa {
let sub = PortSubscribe::empty()?; let sub = PortSubscribe::empty()?;
sub.set_sender(src_pinfo.addr()); 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.seq.subscribe_port(&sub)?;
self.subscription = Some(sub); self.subscription = Some(sub);
self.init_trigger()?; self.init_trigger()?;
@ -413,26 +459,35 @@ impl MidiInput for MidiInputAlsa {
Ok(()) Ok(())
} }
fn device_events(&mut self, ts: mpsc::Sender<Option<MidiPort<Self::DeviceAddr>>>, (tss, rss): (mpsc::Sender<bool>, mpsc::Receiver<bool>)) -> Result<(), Error> { fn device_events(
&mut self,
ts: mpsc::Sender<Option<MidiPort<Self::DeviceAddr>>>,
(tss, rss): (mpsc::Sender<bool>, mpsc::Receiver<bool>),
) -> Result<(), Error> {
let ports = self.ports()?; let ports = self.ports()?;
let port = self.filter_ports(ports, PortFilter::Name(ANNOUNCE_ADDR.to_string())); let port = self.filter_ports(ports, PortFilter::Name(ANNOUNCE_ADDR.to_string()));
self.connect(&port[0].addr, CLIENT_NAME_ANNOUNCE)?; self.connect(&port[0].addr, CLIENT_NAME_ANNOUNCE)?;
self.threaded_alsa_input(move |s: &Self, ev: alsa::seq::Event, _| -> Result<bool, Error> { self.threaded_alsa_input(
// handle disconnect event on watched port move |s: &Self, ev: alsa::seq::Event, _| -> Result<bool, Error> {
match ev.get_type() { // handle disconnect event on watched port
EventType::PortStart => { match ev.get_type() {
if let Some(a) = ev.get_data::<alsa::seq::Addr>() { EventType::PortStart => {
let p = s.ports()?; if let Some(a) = ev.get_data::<alsa::seq::Addr>() {
let pp = s.filter_ports(p, PortFilter::Addr( a.into() ) ); let p = s.ports()?;
if !pp.is_empty() { let pp = s.filter_ports(p, PortFilter::Addr(a.into()));
ts.send(Some(pp[0].clone())).expect("unexpected send() error"); if !pp.is_empty() {
} ts.send(Some(pp[0].clone()))
}; .expect("unexpected send() error");
Ok(false) }
};
Ok(false)
}
_ => Ok(false),
} }
_ => Ok(false), },
} (tss, rss),
}, (tss, rss), ())?; (),
)?;
self.close_internal(); self.close_internal();
Ok(()) Ok(())
} }
@ -441,15 +496,24 @@ impl MidiInput for MidiInputAlsa {
Self::signal_stop_input_internal(self.stop_trigger[1]) Self::signal_stop_input_internal(self.stop_trigger[1])
} }
fn handle_input<F, D>(&mut self, callback: F, (ts, rs): (mpsc::Sender<bool>, mpsc::Receiver<bool>), userdata: D) -> Result<(), Error> fn handle_input<F, D>(
&mut self,
callback: F,
(ts, rs): (mpsc::Sender<bool>, mpsc::Receiver<bool>),
userdata: D,
) -> Result<(), Error>
where where
F: Fn(&Self, &[u8], Option<SystemTime>, &mut D) + Send + Sync, F: Fn(&Self, &[u8], Option<SystemTime>, &mut D) + Send + Sync,
D: Send, D: Send,
{ {
self.threaded_handler(Self::binary_input_handler, self.threaded_handler(
|s, t, m, d| -> Result<(),Error> { Self::binary_input_handler,
callback(s,m,t,d); |s, t, m, d| -> Result<(), Error> {
callback(s, m, t, d);
Ok(()) Ok(())
}, (ts, rs), userdata) },
(ts, rs),
userdata,
)
} }
} }

View file

@ -1,13 +1,12 @@
use crate::util::InternalTryFrom; use crate::util::InternalTryFrom;
pub use super::input::{MidiInput,MidiInputHandler}; pub use super::input::{MidiInput, MidiInputHandler};
pub trait Builder<D, R> { pub trait Builder<D, R> {
fn build<T>(&self) -> fn(&T, D) -> R fn build<T>(&self) -> fn(&T, D) -> R
where where
T: MidiInputHandler+MidiInput+Send+'static, T: MidiInputHandler + MidiInput + Send + 'static,
<T as MidiInputHandler>::DeviceAddr: std::fmt::Display+'static+InternalTryFrom<String>, <T as MidiInputHandler>::DeviceAddr: std::fmt::Display + 'static + InternalTryFrom<String>;
;
} }
macro_rules! builder { macro_rules! builder {
@ -16,12 +15,13 @@ macro_rules! builder {
impl Builder<$intype, $rettype> for $name { impl Builder<$intype, $rettype> for $name {
fn build<T>(&self) -> fn(&T, $intype) -> $rettype fn build<T>(&self) -> fn(&T, $intype) -> $rettype
where where
T: MidiInputHandler+Send+'static, T: MidiInputHandler + Send + 'static,
<T as MidiInputHandler>::DeviceAddr: std::fmt::Display+'static+InternalTryFrom<String>, <T as MidiInputHandler>::DeviceAddr:
std::fmt::Display + 'static + InternalTryFrom<String>,
{ {
$fct $fct
} }
} }
}; };
} }
pub(crate) use builder; pub(crate) use builder;

View file

@ -1,6 +1,6 @@
use serde::Deserialize; use serde::Deserialize;
#[derive(Deserialize,Debug,Clone,Copy,Eq,PartialEq)] #[derive(Deserialize, Debug, Clone, Copy, Eq, PartialEq)]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
pub enum MidiDriver { pub enum MidiDriver {
ALSA, ALSA,

View file

@ -1,57 +1,83 @@
use crate::util::InternalTryFrom;
use crate::{Error, constant};
use crate::config::DeviceConfig; use crate::config::DeviceConfig;
use crate::eventmap::EventMap;
use crate::event::{Event, EventBuf}; use crate::event::{Event, EventBuf};
use crate::eventmap::EventMap;
use crate::util::InternalTryFrom;
use crate::{constant, Error};
use std::str::FromStr; use std::str::FromStr;
use std::sync::{mpsc, Arc, Mutex};
use std::thread; use std::thread;
use std::time::{SystemTime, Instant}; use std::time::{Instant, SystemTime};
use std::sync::{mpsc, Mutex, Arc};
use queues::{CircularBuffer, IsQueue}; use queues::{CircularBuffer, IsQueue};
use super::{PortFilter, MidiPort}; use super::{MidiPort, PortFilter};
pub trait MidiInput pub trait MidiInput
where where
<Self as MidiInput>::DeviceAddr: Clone+Send+FromStr, <Self as MidiInput>::DeviceAddr: Clone + Send + FromStr,
<Self as MidiInput>::DeviceAddr: InternalTryFrom<std::string::String> <Self as MidiInput>::DeviceAddr: InternalTryFrom<std::string::String>,
{ {
type DeviceAddr; type DeviceAddr;
fn new(client_name: &str) -> Result<Self, Error> fn new(client_name: &str) -> Result<Self, Error>
where Self: Sized; where
Self: Sized;
fn close(self) -> Result<(), Error>; fn close(self) -> Result<(), Error>;
fn ports(&self) -> Result<Vec<MidiPort<Self::DeviceAddr>>, Error>; fn ports(&self) -> Result<Vec<MidiPort<Self::DeviceAddr>>, Error>;
fn filter_ports(&self, ports: Vec<MidiPort<Self::DeviceAddr>>, filter: PortFilter<Self::DeviceAddr>) -> Vec<MidiPort<Self::DeviceAddr>>; fn filter_ports(
&self,
ports: Vec<MidiPort<Self::DeviceAddr>>,
filter: PortFilter<Self::DeviceAddr>,
) -> Vec<MidiPort<Self::DeviceAddr>>;
fn connect(&mut self, port_addr: &Self::DeviceAddr, port_name: &str) -> Result<(), Error>; fn connect(&mut self, port_addr: &Self::DeviceAddr, port_name: &str) -> Result<(), Error>;
fn device_events(&mut self, ts: mpsc::Sender<Option<MidiPort<Self::DeviceAddr>>>, ss: (mpsc::Sender<bool>, mpsc::Receiver<bool>)) -> Result<(), Error>; fn device_events(
&mut self,
ts: mpsc::Sender<Option<MidiPort<Self::DeviceAddr>>>,
ss: (mpsc::Sender<bool>, mpsc::Receiver<bool>),
) -> Result<(), Error>;
fn signal_stop_input(&self) -> Result<(), Error>; fn signal_stop_input(&self) -> Result<(), Error>;
fn handle_input<F, D>(&mut self, callback: F, rts: (mpsc::Sender<bool>, mpsc::Receiver<bool>), userdata: D) -> Result<(), Error> fn handle_input<F, D>(
&mut self,
callback: F,
rts: (mpsc::Sender<bool>, mpsc::Receiver<bool>),
userdata: D,
) -> Result<(), Error>
where where
F: Fn(&Self, &[u8], Option<SystemTime>, &mut D) + Send + Sync, F: Fn(&Self, &[u8], Option<SystemTime>, &mut D) + Send + Sync,
D: Send, D: Send;
;
} }
pub trait MidiInputHandler pub trait MidiInputHandler
where where
Self: Sized, Self: Sized,
<Self as MidiInputHandler>::DeviceAddr: Clone+Send+FromStr, <Self as MidiInputHandler>::DeviceAddr: Clone + Send + FromStr,
{ {
type DeviceAddr; type DeviceAddr;
fn new(client_name: &str) -> Result<Self, Error>; fn new(client_name: &str) -> Result<Self, Error>;
fn ports(&self) -> Result<Vec<MidiPort<Self::DeviceAddr>>, Error>; fn ports(&self) -> Result<Vec<MidiPort<Self::DeviceAddr>>, Error>;
fn try_connect(&self, port: MidiPort<Self::DeviceAddr>, filter: PortFilter<Self::DeviceAddr> ) -> Result<Option<Self>, Error>; fn try_connect(
fn run(&mut self, conf: &DeviceConfig, eventmap: &EventMap, trs: (mpsc::Sender<bool>, mpsc::Receiver<bool>)) -> Result<(), Error>; &self,
fn device_events(&mut self, ts: mpsc::Sender<Option<MidiPort<Self::DeviceAddr>>>, ss: (mpsc::Sender<bool>,mpsc::Receiver<bool>)) -> Result<(), Error>; port: MidiPort<Self::DeviceAddr>,
filter: PortFilter<Self::DeviceAddr>,
) -> Result<Option<Self>, Error>;
fn run(
&mut self,
conf: &DeviceConfig,
eventmap: &EventMap,
trs: (mpsc::Sender<bool>, mpsc::Receiver<bool>),
) -> Result<(), Error>;
fn device_events(
&mut self,
ts: mpsc::Sender<Option<MidiPort<Self::DeviceAddr>>>,
ss: (mpsc::Sender<bool>, mpsc::Receiver<bool>),
) -> Result<(), Error>;
} }
// Generic implementation // Generic implementation
@ -62,7 +88,6 @@ where
<T as MidiInput>::DeviceAddr: FromStr, <T as MidiInput>::DeviceAddr: FromStr,
{ {
type DeviceAddr = T::DeviceAddr; type DeviceAddr = T::DeviceAddr;
fn new(client_name: &str) -> Result<Self, Error> { fn new(client_name: &str) -> Result<Self, Error> {
MidiInput::new(client_name) MidiInput::new(client_name)
@ -72,7 +97,11 @@ where
MidiInput::ports(self) MidiInput::ports(self)
} }
fn try_connect(&self, port: MidiPort<Self::DeviceAddr>, filter: PortFilter<T::DeviceAddr> ) -> Result<Option<Self>, Error> { fn try_connect(
&self,
port: MidiPort<Self::DeviceAddr>,
filter: PortFilter<T::DeviceAddr>,
) -> Result<Option<Self>, Error> {
let portmap = self.ports()?; let portmap = self.ports()?;
let pv = self.filter_ports(portmap, PortFilter::Addr(port.addr)); let pv = self.filter_ports(portmap, PortFilter::Addr(port.addr));
let pv = self.filter_ports(pv, filter); let pv = self.filter_ports(pv, filter);
@ -81,35 +110,44 @@ where
let mut v = T::new(constant::CLIENT_NAME_HANDLER)?; let mut v = T::new(constant::CLIENT_NAME_HANDLER)?;
v.connect(&port.addr, constant::CLIENT_NAME_HANDLER)?; v.connect(&port.addr, constant::CLIENT_NAME_HANDLER)?;
Ok(Some(v)) Ok(Some(v))
} } else {
else {
Ok(None) Ok(None)
} }
} }
fn device_events(&mut self, ts: mpsc::Sender<Option<MidiPort<Self::DeviceAddr>>>, ss: (mpsc::Sender<bool>,mpsc::Receiver<bool>)) -> Result<(), Error> { fn device_events(
&mut self,
ts: mpsc::Sender<Option<MidiPort<Self::DeviceAddr>>>,
ss: (mpsc::Sender<bool>, mpsc::Receiver<bool>),
) -> Result<(), Error> {
self.device_events(ts, ss) self.device_events(ts, ss)
} }
fn run(&mut self, conf: &DeviceConfig, eventmap: &EventMap, (ts, rs): (mpsc::Sender<bool>, mpsc::Receiver<bool>)) -> Result<(), Error> { fn run(
&mut self,
conf: &DeviceConfig,
eventmap: &EventMap,
(ts, rs): (mpsc::Sender<bool>, mpsc::Receiver<bool>),
) -> Result<(), Error> {
thread::scope(|s| -> Result<(), Error> { thread::scope(|s| -> Result<(), Error> {
// parking signal for runner, true = stop // parking signal for runner, true = stop
let (pts,prs) = mpsc::channel::<bool>(); let (pts, prs) = mpsc::channel::<bool>();
// event queue populated by the main thread and consumed by the exec thread // event queue populated by the main thread and consumed by the exec thread
let evq = Arc::new(Mutex::new(CircularBuffer::<EventBuf>::new(conf.queue_length))); let evq = Arc::new(Mutex::new(CircularBuffer::<EventBuf>::new(
conf.queue_length,
)));
// background execution loop // background execution loop
let rq = evq.clone(); let rq = evq.clone();
let exec_thread = s.spawn(move || -> Result<(),Error> { let exec_thread = s.spawn(move || -> Result<(), Error> {
loop { loop {
if prs.recv()? { if prs.recv()? {
break; break;
} }
loop { loop {
// nest the lock into a scope to release it before run // 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(); let mut evq = rq.lock().unwrap();
if evq.size() > 0 { if evq.size() > 0 {
(evq.remove().unwrap(), Instant::now()) (evq.remove().unwrap(), Instant::now())
@ -117,7 +155,9 @@ where
break; 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 // wait until interval has been reached
let elapsed_time = start.elapsed(); let elapsed_time = start.elapsed();
if elapsed_time < conf.interval { if elapsed_time < conf.interval {
@ -127,23 +167,26 @@ where
} }
Ok(()) Ok(())
}); });
self.handle_input(|_,m,t,(evq,pts)| { self.handle_input(
let mut event: EventBuf = Event::from(m).into(); |_, m, t, (evq, pts)| {
event.timestamp = t; let mut event: EventBuf = Event::from(m).into();
if conf.log { event.timestamp = t;
println!("{}: event: {}", constant::CLIENT_NAME, event); if conf.log {
} println!("{}: event: {}", constant::CLIENT_NAME, event);
let mut evq = evq.lock().unwrap(); }
evq.add(event).unwrap(); let mut evq = evq.lock().unwrap();
pts.send(false).expect("unexpected write error"); evq.add(event).unwrap();
}, (ts,rs), (evq,pts.clone()))?; pts.send(false).expect("unexpected write error");
},
(ts, rs),
(evq, pts.clone()),
)?;
pts.send(true).expect("unexpected write error"); pts.send(true).expect("unexpected write error");
let _ = exec_thread.join(); let _ = exec_thread.join();
Ok(()) Ok(())
})?; })?;
Ok(()) Ok(())
} }

View file

@ -1,20 +1,20 @@
pub mod backend; pub mod backend;
pub mod port;
pub mod portfilter;
pub mod input;
pub mod builder; pub mod builder;
pub mod driver; pub mod driver;
pub mod input;
pub mod port;
pub mod portfilter;
use crate::Error; use crate::Error;
extern crate libc; extern crate libc;
pub use driver::MidiDriver;
pub use builder::Builder; pub use builder::Builder;
pub use driver::MidiDriver;
pub use input::{MidiInput, MidiInputHandler};
pub use port::MidiPort; pub use port::MidiPort;
pub use portfilter::PortFilter; pub use portfilter::PortFilter;
pub use input::{MidiInput,MidiInputHandler};
pub enum MidiHandler { pub enum MidiHandler {
ALSA(backend::MidiInputAlsa), ALSA(backend::MidiInputAlsa),
@ -35,7 +35,7 @@ impl MidiHandler {
// wrap generic functions into builder because functions with generic traits cannot be passed as arguments // wrap generic functions into builder because functions with generic traits cannot be passed as arguments
pub fn builder_handler<B, D, R>(&mut self, builder: B, data: D) -> R pub fn builder_handler<B, D, R>(&mut self, builder: B, data: D) -> R
where where
B: Builder<D,R>, B: Builder<D, R>,
D: Send, D: Send,
{ {
match self { match self {

View file

@ -1,21 +1,19 @@
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
#[derive(Eq, PartialEq, Debug, Clone)]
#[derive(Eq,PartialEq,Debug,Clone)]
pub struct MidiPort<T> pub struct MidiPort<T>
where where
T: Clone T: Clone,
{ {
pub name: String, pub name: String,
pub addr: T, pub addr: T,
} }
impl<T> Display for MidiPort<T> impl<T> Display for MidiPort<T>
where where
T: Display+Clone T: Display + Clone,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}\t{}", self.addr, self.name) write!(f, "{}\t{}", self.addr, self.name)
} }
} }

View file

@ -1,18 +1,16 @@
use crate::Error;
use crate::config::DeviceConfig;
use crate::config::device::Identifier; use crate::config::device::Identifier;
use crate::config::DeviceConfig;
use crate::util::InternalTryFrom; use crate::util::InternalTryFrom;
use crate::Error;
#[derive(Debug, Clone)]
#[derive(Debug,Clone)] pub enum PortFilter<T> {
pub enum PortFilter<T>{
All, All,
Name(String), Name(String),
Regex(regex::Regex), Regex(regex::Regex),
Addr(T), Addr(T),
} }
impl<T> InternalTryFrom<&DeviceConfig> for PortFilter<T> impl<T> InternalTryFrom<&DeviceConfig> for PortFilter<T>
where where
T: InternalTryFrom<String>, T: InternalTryFrom<String>,
@ -25,4 +23,4 @@ where
Identifier::Addr(s) => PortFilter::Addr(T::i_try_from(s.to_string())?), Identifier::Addr(s) => PortFilter::Addr(T::i_try_from(s.to_string())?),
}) })
} }
} }

View file

@ -1,29 +1,36 @@
use std::sync::mpsc; use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
use std::sync::{Mutex,Arc};
use libc::SIGUSR1; use libc::SIGUSR1;
use signal_hook::iterator::Signals; use signal_hook::iterator::Signals;
use crate::util::InternalTryFrom; use crate::config::{Config, DeviceConfig};
use crate::{Error, constant};
use crate::midi::{PortFilter,MidiInputHandler, MidiPort, Builder};
use crate::config::{Config,DeviceConfig};
use crate::eventmap::EventMap; use crate::eventmap::EventMap;
use crate::midi::builder::builder; 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<Arc<Mutex<(u32, u32)>>>); type DeviceRunItem<'a> = (
type DeviceRunResult<'a> =(thread::ScopedJoinHandle<'a, Result<(), Error>>, mpsc::Sender<bool>); &'a DeviceConfig,
EventMap<'a>,
Option<Arc<Mutex<(u32, u32)>>>,
);
type DeviceRunResult<'a> = (
thread::ScopedJoinHandle<'a, Result<(), Error>>,
mpsc::Sender<bool>,
);
pub fn cross_shell(cmd: &str) -> Vec<String> { pub fn cross_shell(cmd: &str) -> Vec<String> {
if cfg!(target_os = "windows") { if cfg!(target_os = "windows") {
vec!("cmd", "/C", cmd) vec!["cmd", "/C", cmd]
} else { } else {
vec!("sh", "-c", cmd) vec!["sh", "-c", cmd]
} }
.iter().map( .iter()
|x| x.to_string() .map(|x| x.to_string())
).collect() .collect()
} }
builder!(ListDevicesBuilder, list_devices, (), Result<(), Error>); builder!(ListDevicesBuilder, list_devices, (), Result<(), Error>);
@ -31,8 +38,8 @@ builder!(RunConfigBuilder, run_config, &Config, Result<(), Error>);
pub fn list_devices<T>(input: &T, _: ()) -> Result<(), Error> pub fn list_devices<T>(input: &T, _: ()) -> Result<(), Error>
where where
T: MidiInputHandler+Send+'static, T: MidiInputHandler + Send + 'static,
<T as MidiInputHandler>::DeviceAddr: 'static+std::fmt::Display, <T as MidiInputHandler>::DeviceAddr: 'static + std::fmt::Display,
{ {
let ports = MidiInputHandler::ports(input)?; let ports = MidiInputHandler::ports(input)?;
println!(" Addr\t Name"); println!(" Addr\t Name");
@ -44,17 +51,23 @@ where
pub fn run_config<T>(input: &T, conf: &Config) -> Result<(), Error> pub fn run_config<T>(input: &T, conf: &Config) -> Result<(), Error>
where where
T: MidiInputHandler+Send+'static, T: MidiInputHandler + Send + 'static,
<T as MidiInputHandler>::DeviceAddr: 'static+std::fmt::Display+InternalTryFrom<String>, <T as MidiInputHandler>::DeviceAddr: 'static + std::fmt::Display + InternalTryFrom<String>,
{ {
let cfevmap: Vec<DeviceRunItem> = conf.devices.iter().map(|x| let cfevmap: Vec<DeviceRunItem> = conf
(x, EventMap::from(x), .devices
x.max_connections.map(|v| (Arc::new(Mutex::new((0,v))))) .iter()
) .map(|x| {
).collect(); (
x,
EventMap::from(x),
x.max_connections.map(|v| (Arc::new(Mutex::new((0, v))))),
)
})
.collect();
let (tdev,rdev) = mpsc::channel::<Option<MidiPort<T::DeviceAddr>>>(); let (tdev, rdev) = mpsc::channel::<Option<MidiPort<T::DeviceAddr>>>();
let (tsd,rsd) = mpsc::channel::<bool>(); let (tsd, rsd) = mpsc::channel::<bool>();
let ntsd = tsd.clone(); let ntsd = tsd.clone();
let ntdev = tdev.clone(); let ntdev = tdev.clone();
@ -77,12 +90,14 @@ where
let mut threads: Vec<DeviceRunResult> = Vec::new(); let mut threads: Vec<DeviceRunResult> = Vec::new();
let ports = input.ports()?; let ports = input.ports()?;
for p in 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 event_thread = s.spawn(move || {
let mut input = T::new(constant::CLIENT_NAME_EVENT).unwrap(); 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(); tdev.send(None).unwrap();
r r
}); });
@ -96,12 +111,17 @@ where
if conf.log { if conf.log {
println!("{}: device connect: {}", constant::CLIENT_NAME, p); 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()?; event_thread.join().unwrap()?;
for (thread,ss) in threads { for (thread, ss) in threads {
let _ = ss.send(true); 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(()) Ok(())
})?; })?;
@ -112,12 +132,11 @@ fn try_connect_process<'a, T>(
input: &T, input: &T,
s: &'a thread::Scope<'a, '_>, s: &'a thread::Scope<'a, '_>,
p: &MidiPort<T::DeviceAddr>, p: &MidiPort<T::DeviceAddr>,
cfevmap: &'a[DeviceRunItem<'a>], cfevmap: &'a [DeviceRunItem<'a>],
) ) -> Result<Option<DeviceRunResult<'a>>, Error>
-> Result<Option<DeviceRunResult<'a>>, Error>
where where
T: MidiInputHandler+Send+'static, T: MidiInputHandler + Send + 'static,
<T as MidiInputHandler>::DeviceAddr: 'static+InternalTryFrom<String>, <T as MidiInputHandler>::DeviceAddr: 'static + InternalTryFrom<String>,
{ {
for (dev, eventmap, counter) in cfevmap { for (dev, eventmap, counter) in cfevmap {
// device counter is full // device counter is full
@ -135,13 +154,13 @@ where
m.0 += 1; m.0 += 1;
} }
// stop signal channel // stop signal channel
let (sts,srs) = mpsc::channel::<bool>(); let (sts, srs) = mpsc::channel::<bool>();
let mm = counter.as_ref().map(Arc::clone); let mm = counter.as_ref().map(Arc::clone);
let nsts = sts.clone(); let nsts = sts.clone();
let t = s.spawn( move || -> Result<(), Error> { let t = s.spawn(move || -> Result<(), Error> {
dev.run_connect()?; dev.run_connect()?;
// blocking process // blocking process
c.run(dev, eventmap, (nsts,srs))?; c.run(dev, eventmap, (nsts, srs))?;
// decrease device counter // decrease device counter
if let Some(m) = mm { if let Some(m) = mm {
let mut m = m.lock().unwrap(); let mut m = m.lock().unwrap();

View file

@ -1,13 +1,11 @@
pub mod smartset;
pub mod range; pub mod range;
pub mod remap; pub mod remap;
pub mod smartset;
pub type SmartSet<T> = smartset::SmartSet<T>; pub type SmartSet<T> = smartset::SmartSet<T>;
pub type Range<T> = range::Range<T>; pub type Range<T> = range::Range<T>;
pub type Remapper<T> = remap::Remapper<T>; pub type Remapper<T> = remap::Remapper<T>;
macro_rules! visit_from { macro_rules! visit_from {
( $obj:ident , $( ($fct:ident, $type:ty) ),+ $(,)?) => { ( $obj:ident , $( ($fct:ident, $type:ty) ),+ $(,)?) => {
$( $(
@ -23,21 +21,25 @@ macro_rules! visit_from {
pub(crate) use visit_from; pub(crate) use visit_from;
pub fn map_tryfrom<S,D>(v: Vec<S>) -> Result<Vec<D>, <D as TryFrom<S>>::Error> pub fn map_tryfrom<S, D>(v: Vec<S>) -> Result<Vec<D>, <D as TryFrom<S>>::Error>
where where
D: TryFrom<S>, D: TryFrom<S>,
{ {
v.into_iter().map(|x| D::try_from(x)).collect::<Result<Vec<D>, <D as TryFrom<S>>::Error>>() v.into_iter()
.map(|x| D::try_from(x))
.collect::<Result<Vec<D>, <D as TryFrom<S>>::Error>>()
} }
pub fn map_opt_tryfrom<S,D>(v: Option<Vec<S>>) -> Result<Option<Vec<D>>, <D as TryFrom<S>>::Error> pub fn map_opt_tryfrom<S, D>(v: Option<Vec<S>>) -> Result<Option<Vec<D>>, <D as TryFrom<S>>::Error>
where where
D: TryFrom<S>, D: TryFrom<S>,
{ {
match v { match v {
Some(v) => { Some(v) => Ok(Some(
Ok( Some(v.into_iter().map(|x| D::try_from(x)).collect::<Result<Vec<D>, <D as TryFrom<S>>::Error>>()?) ) v.into_iter()
} .map(|x| D::try_from(x))
.collect::<Result<Vec<D>, <D as TryFrom<S>>::Error>>()?,
)),
None => Ok(None), None => Ok(None),
} }
} }

View file

@ -1,36 +1,34 @@
use std::str::FromStr;
use std::cmp::PartialOrd; use std::cmp::PartialOrd;
use std::str::FromStr;
use num::{Num,NumCast}; use num::{Num, NumCast};
use super::visit_from; use super::visit_from;
// Trait aliases are unstable // Trait aliases are unstable
//trait smartsetnum = T: Num+Copy + FromStr; //trait smartsetnum = T: Num+Copy + FromStr;
#[derive(Debug,Clone,Copy)] #[derive(Debug, Clone, Copy)]
pub struct Range<T> pub struct Range<T>
where where
T: Num+Copy + FromStr + PartialOrd, T: Num + Copy + FromStr + PartialOrd,
{ {
start: T, start: T,
end: T, end: T,
} }
pub fn parse_range<T>(s: &str) -> Result<Range<T>, <T as FromStr>::Err> pub fn parse_range<T>(s: &str) -> Result<Range<T>, <T as FromStr>::Err>
where where
T: Num+Copy + FromStr + PartialOrd, T: Num + Copy + FromStr + PartialOrd,
{ {
let mut osep = s.find(':'); let mut osep = s.find(':');
if osep.is_none() { if osep.is_none() {
osep = s.find('-'); osep = s.find('-');
} }
let r = if let Some(sep) = osep { let r = if let Some(sep) = osep {
let (p1,p2) = (&s[..sep], &s[sep+1..] ); let (p1, p2) = (&s[..sep], &s[sep + 1..]);
( p1.parse()?, p2.parse()? ) (p1.parse()?, p2.parse()?)
} } else {
else {
let n = s.parse()?; let n = s.parse()?;
(n, n) (n, n)
}; };
@ -39,13 +37,10 @@ T: Num+Copy + FromStr + PartialOrd,
impl<T> Range<T> impl<T> Range<T>
where where
T: Num+Copy + FromStr + PartialOrd, T: Num + Copy + FromStr + PartialOrd,
{ {
pub fn new(start: T, end: T) -> Self { pub fn new(start: T, end: T) -> Self {
Self { Self { start, end }
start,
end,
}
} }
pub fn start(&self) -> T { pub fn start(&self) -> T {
@ -57,10 +52,10 @@ T: Num+Copy + FromStr + PartialOrd,
} }
} }
impl<T,U> From<U> for Range<T> impl<T, U> From<U> for Range<T>
where where
T: Num+Copy+NumCast + FromStr + PartialOrd, T: Num + Copy + NumCast + FromStr + PartialOrd,
U: Num+Copy+num::ToPrimitive + FromStr, U: Num + Copy + num::ToPrimitive + FromStr,
{ {
fn from(i: U) -> Self { fn from(i: U) -> Self {
let ti: T = num::NumCast::from(i).unwrap(); let ti: T = num::NumCast::from(i).unwrap();
@ -70,7 +65,7 @@ where
impl<T> FromStr for Range<T> impl<T> FromStr for Range<T>
where where
T: Num+Copy + FromStr + PartialOrd, T: Num + Copy + FromStr + PartialOrd,
{ {
type Err = <T as FromStr>::Err; type Err = <T as FromStr>::Err;
@ -79,32 +74,31 @@ where
} }
} }
use std::marker::PhantomData; use serde::de::{self, Deserialize, Deserializer, Visitor};
use std::fmt; use std::fmt;
use serde::de::{self,Deserialize, Deserializer, Visitor}; use std::marker::PhantomData;
struct RangeVisitor<T> struct RangeVisitor<T>
where where
T: Num+Copy + FromStr + PartialOrd, T: Num + Copy + FromStr + PartialOrd,
{ {
marker: PhantomData<fn() -> Range<T>> marker: PhantomData<fn() -> Range<T>>,
} }
impl<T> RangeVisitor<T> impl<T> RangeVisitor<T>
where where
T: Num+Copy + FromStr + PartialOrd, T: Num + Copy + FromStr + PartialOrd,
{ {
fn new() -> Self { fn new() -> Self {
Self { Self {
marker: PhantomData marker: PhantomData,
} }
} }
} }
impl<'de, T> Visitor<'de> for RangeVisitor<T> impl<'de, T> Visitor<'de> for RangeVisitor<T>
where where
T: Num+Copy+PartialOrd + FromStr +NumCast + Deserialize<'de> + std::fmt::Debug, T: Num + Copy + PartialOrd + FromStr + NumCast + Deserialize<'de> + std::fmt::Debug,
<T as FromStr>::Err: std::fmt::Display, <T as FromStr>::Err: std::fmt::Display,
{ {
type Value = Range<T>; type Value = Range<T>;
@ -113,7 +107,7 @@ where
formatter.write_str("a set of integer") formatter.write_str("a set of integer")
} }
visit_from!{ Range , visit_from! { Range ,
(visit_i8, i8), (visit_i8, i8),
(visit_i16, i16), (visit_i16, i16),
(visit_i32, i32), (visit_i32, i32),
@ -135,7 +129,7 @@ where
// This is the trait that informs Serde how to deserialize MyMap. // This is the trait that informs Serde how to deserialize MyMap.
impl<'de, T> Deserialize<'de> for Range<T> impl<'de, T> Deserialize<'de> for Range<T>
where where
T: Num+Copy+NumCast+PartialOrd + Deserialize<'de> + FromStr + std::fmt::Debug, T: Num + Copy + NumCast + PartialOrd + Deserialize<'de> + FromStr + std::fmt::Debug,
<T as FromStr>::Err: std::fmt::Display, <T as FromStr>::Err: std::fmt::Display,
{ {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>

View file

@ -1,17 +1,25 @@
use num::{Bounded, Num, NumCast, ToPrimitive};
use num::{Num,NumCast,ToPrimitive, Bounded};
use std::str::FromStr;
use std::ops; use std::ops;
use std::str::FromStr;
use super::Range; use super::Range;
// Trait aliases are unstable // Trait aliases are unstable
//trait remapnum = T: Num+ToPrimitive+Copy+PartialOrd + FromStr + ops::Add + ops::Sub + ops::Div + ops::Mul; //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<T> pub struct Remapper<T>
where 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<T>, src: Range<T>,
dst: Range<T>, dst: Range<T>,
@ -19,9 +27,18 @@ where
impl<T> Remapper<T> impl<T> Remapper<T>
where 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<T> { pub fn src(&self) -> &Range<T> {
&self.src &self.src
} }
@ -31,17 +48,13 @@ where
} }
pub fn new(src: Range<T>, dst: Range<T>) -> Self { pub fn new(src: Range<T>, dst: Range<T>) -> Self {
Self { Self { src, dst }
src,
dst,
}
} }
pub fn remap(&self, v: T) -> T pub fn remap(&self, v: T) -> T {
{
// compute actual value in source type // compute actual value in source type
let r: T = (v-self.src.start())*(self.dst.end()-self.dst.start()) let r: T = (v - self.src.start()) * (self.dst.end() - self.dst.start())
/ (self.src.end()-self.src.start()) / (self.src.end() - self.src.start())
+ self.dst.start(); + self.dst.start();
r r
} }
@ -49,30 +62,39 @@ where
impl<T> Remapper<T> impl<T> Remapper<T>
where 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<U>(&self, v: T) -> Option<U> pub fn remap_to<U>(&self, v: T) -> Option<U>
where where
U: Num+NumCast+Copy+Bounded + FromStr, U: Num + NumCast + Copy + Bounded + FromStr,
{ {
// compute actual value in source type // compute actual value in source type
let r: T = self.remap(v); let r: T = self.remap(v);
// find min/max values of target type // find min/max values of target type
let (rmin,rmax): (Option<T>,Option<T>) = ( let (rmin, rmax): (Option<T>, Option<T>) = (
num::NumCast::from(U::min_value()), num::NumCast::from(U::min_value()),
num::NumCast::from(U::max_value()), num::NumCast::from(U::max_value()),
); );
// if target min/max can be casted onto source, bound output to those // if target min/max can be casted onto source, bound output to those
match (rmin,rmax) { match (rmin, rmax) {
(Some(min),Some(max)) => { (Some(min), Some(max)) => {
if r >= max { if r >= max {
Some(U::max_value()) Some(U::max_value())
} else if r <= min { } else if r <= min {
Some(U::min_value()) Some(U::min_value())
} } else {
else {
num::NumCast::from(r) num::NumCast::from(r)
} }
} }

View file

@ -1,10 +1,9 @@
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::str::FromStr;
use std::ops; use std::ops;
use std::str::FromStr;
use num::{Num,NumCast}; use num::{Num, NumCast};
use thiserror::Error; use thiserror::Error;
@ -13,9 +12,8 @@ use thiserror::Error;
pub fn parse_int_set<T>(s: &str) -> Result<BTreeSet<T>, <T as std::str::FromStr>::Err> pub fn parse_int_set<T>(s: &str) -> Result<BTreeSet<T>, <T as std::str::FromStr>::Err>
where where
T: Num+Ord+Copy + std::str::FromStr + ops::AddAssign, T: Num + Ord + Copy + std::str::FromStr + ops::AddAssign,
{ {
let mut r: BTreeSet<T> = BTreeSet::new(); let mut r: BTreeSet<T> = BTreeSet::new();
let parts: Vec<&str> = s.split(',').collect(); let parts: Vec<&str> = s.split(',').collect();
for p in parts { for p in parts {
@ -25,11 +23,11 @@ where
osep = s.find('-'); osep = s.find('-');
} }
if let Some(sep) = osep { if let Some(sep) = osep {
let (p1,p2) = (&s[..sep], &s[sep+1..] ); let (p1, p2) = (&s[..sep], &s[sep + 1..]);
let (low,high): (T,T) = ( p1.parse()?, p2.parse()? ); let (low, high): (T, T) = (p1.parse()?, p2.parse()?);
let (mut low,high) = match low <= high { let (mut low, high) = match low <= high {
true => (low,high), true => (low, high),
false => (high,low), false => (high, low),
}; };
r.insert(low); r.insert(low);
loop { loop {
@ -39,8 +37,7 @@ where
} }
low += T::one(); low += T::one();
} }
} } else {
else {
r.insert(p.parse()?); r.insert(p.parse()?);
} }
} }
@ -48,17 +45,17 @@ where
Ok(r) Ok(r)
} }
#[derive(Debug,Clone)] #[derive(Debug, Clone)]
pub struct SmartSet<T> pub struct SmartSet<T>
where where
T: Num+Ord+Copy + std::str::FromStr + ops::AddAssign, T: Num + Ord + Copy + std::str::FromStr + ops::AddAssign,
{ {
pub set: BTreeSet<T> pub set: BTreeSet<T>,
} }
impl<T> SmartSet<T> impl<T> SmartSet<T>
where where
T: Num+Ord+Copy + std::str::FromStr + ops::AddAssign, T: Num + Ord + Copy + std::str::FromStr + ops::AddAssign,
{ {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@ -77,7 +74,7 @@ where
impl<T> From<T> for SmartSet<T> impl<T> From<T> for SmartSet<T>
where 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 { fn from(i: T) -> Self {
SmartSet { SmartSet {
@ -86,20 +83,20 @@ where
} }
} }
#[derive(Error,Debug)] #[derive(Error, Debug)]
pub enum Error<T> pub enum Error<T>
where where
T: std::fmt::Display, T: std::fmt::Display,
{ {
#[error("invalid type: `{0}`, expected {1}")] #[error("invalid type: `{0}`, expected {1}")]
Cast(T,String), Cast(T, String),
#[error("unknown error")] #[error("unknown error")]
Unknown, Unknown,
} }
trait InternalTryFrom<T> trait InternalTryFrom<T>
where where
Self: Sized Self: Sized,
{ {
type Error; type Error;
fn i_try_from(other: T) -> Result<Self, Self::Error>; fn i_try_from(other: T) -> Result<Self, Self::Error>;
@ -107,19 +104,17 @@ where
impl<T, U> InternalTryFrom<U> for SmartSet<T> impl<T, U> InternalTryFrom<U> for SmartSet<T>
where where
T: Num+Ord+Copy+NumCast + std::str::FromStr + ops::AddAssign, T: Num + Ord + Copy + NumCast + std::str::FromStr + ops::AddAssign,
U: Num+Ord+Copy+num::ToPrimitive + std::str::FromStr + ops::AddAssign + std::fmt::Display, U: Num + Ord + Copy + num::ToPrimitive + std::str::FromStr + ops::AddAssign + std::fmt::Display,
{ {
type Error = Error<U>; type Error = Error<U>;
fn i_try_from(i: U) -> Result<Self, Self::Error> { fn i_try_from(i: U) -> Result<Self, Self::Error> {
// let mut r = SmartSet::<T>::new(); // let mut r = SmartSet::<T>::new();
match num::NumCast::from(i) { match num::NumCast::from(i) {
Some(v) => { Some(v) => Ok(SmartSet {
Ok(SmartSet { set: BTreeSet::from([v]),
set: BTreeSet::from([v]), }),
}) _ => Err(Error::Cast(i, std::any::type_name::<T>().to_string())),
}
_ => Err(Error::Cast(i, std::any::type_name::<T>().to_string()))
} }
} }
} }
@ -141,7 +136,7 @@ where
impl<T> FromStr for SmartSet<T> impl<T> FromStr for SmartSet<T>
where where
T: Num+Ord+Copy + std::str::FromStr + ops::AddAssign, T: Num + Ord + Copy + std::str::FromStr + ops::AddAssign,
{ {
type Err = <T as FromStr>::Err; type Err = <T as FromStr>::Err;
@ -154,7 +149,7 @@ where
impl<T> IntoIterator for SmartSet<T> impl<T> IntoIterator for SmartSet<T>
where where
T: Num+Ord+Copy + std::str::FromStr + ops::AddAssign, T: Num + Ord + Copy + std::str::FromStr + ops::AddAssign,
{ {
type Item = T; type Item = T;
type IntoIter = std::collections::btree_set::IntoIter<Self::Item>; type IntoIter = std::collections::btree_set::IntoIter<Self::Item>;
@ -166,7 +161,7 @@ where
impl<'a, T> IntoIterator for &'a SmartSet<T> impl<'a, T> IntoIterator for &'a SmartSet<T>
where where
T: Num+Ord+Copy + std::str::FromStr + ops::AddAssign, T: Num + Ord + Copy + std::str::FromStr + ops::AddAssign,
{ {
type Item = &'a T; type Item = &'a T;
type IntoIter = std::collections::btree_set::Iter<'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 std::fmt;
use serde::de::{self,Deserialize, Deserializer, Visitor}; use std::marker::PhantomData;
struct SmartSetVisitor<T> struct SmartSetVisitor<T>
where where
T: Num+Ord+Copy + std::str::FromStr + ops::AddAssign, T: Num + Ord + Copy + std::str::FromStr + ops::AddAssign,
{ {
marker: PhantomData<fn() -> SmartSet<T>> marker: PhantomData<fn() -> SmartSet<T>>,
} }
impl<T> SmartSetVisitor<T> impl<T> SmartSetVisitor<T>
where where
T: Num+Ord+Copy + std::str::FromStr + ops::AddAssign, T: Num + Ord + Copy + std::str::FromStr + ops::AddAssign,
{ {
fn new() -> Self { fn new() -> Self {
Self { Self {
marker: PhantomData marker: PhantomData,
} }
} }
} }
@ -214,7 +208,14 @@ macro_rules! visit_from {
impl<'de, T> Visitor<'de> for SmartSetVisitor<T> impl<'de, T> Visitor<'de> for SmartSetVisitor<T>
where 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,
<T as FromStr>::Err: std::fmt::Display, <T as FromStr>::Err: std::fmt::Display,
{ {
type Value = SmartSet<T>; type Value = SmartSet<T>;
@ -223,7 +224,7 @@ where
formatter.write_str("a set of integer") formatter.write_str("a set of integer")
} }
visit_from!{ visit_from! {
(visit_i8, i8), (visit_i8, i8),
(visit_i16, i16), (visit_i16, i16),
(visit_i32, i32), (visit_i32, i32),
@ -250,12 +251,14 @@ where
loop { loop {
if let Ok(Some(value)) = seq.next_element::<String>() { if let Ok(Some(value)) = seq.next_element::<String>() {
r.set.extend(&SmartSet::<T>::from_str(&value).map_err(serde::de::Error::custom)?.set); r.set.extend(
} &SmartSet::<T>::from_str(&value)
else if let Some(value) = seq.next_element()? { .map_err(serde::de::Error::custom)?
.set,
);
} else if let Some(value) = seq.next_element()? {
r.set.insert(value); r.set.insert(value);
} } else {
else {
break; break;
} }
} }
@ -267,7 +270,14 @@ where
// This is the trait that informs Serde how to deserialize MyMap. // This is the trait that informs Serde how to deserialize MyMap.
impl<'de, T> Deserialize<'de> for SmartSet<T> impl<'de, T> Deserialize<'de> for SmartSet<T>
where 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,
<T as FromStr>::Err: std::fmt::Display, <T as FromStr>::Err: std::fmt::Display,
{ {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>