1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
use serde::{Serialize,Deserialize,Serializer,Deserializer};
use std::collections::BTreeMap;
use swaystatus_plugin::*;
use std::ops::{Add, Sub};
use std::str::FromStr;
use std::num::{ParseIntError,IntErrorKind};
#[derive(Serialize, Deserialize)]
#[serde(tag = "Sink")]
pub(crate) enum Sink {
Default,
Specific {
sink_name : String
}
}
#[derive(Serialize, Deserialize)]
#[serde(tag = "Format")]
enum FormatableVolume<KeyTypeMetadata : VolumeKeyBackingTypeMetadata> {
Off,
Numeric {
label : String
},
Binned {
label: String,
bin_symbol_map : BTreeMap<VolumeKey<KeyTypeMetadata>,String>
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "PascalCase", default)]
pub struct PulseVolumeConfig {
pub(crate) sink : Sink,
volume : FormatableVolume<VolumeKeyVolume>,
balance : FormatableVolume<VolumeKeyBalance>
}
impl Default for PulseVolumeConfig {
fn default() -> Self {
PulseVolumeConfig {
sink : Sink::Default,
volume : FormatableVolume::Numeric { label : String::new() },
//volume : FormatableVolume::Binned { label : String::new(), bin_symbol_map : {let mut a = BTreeMap::new(); a.insert(4,String::from("Blah")); a}},
balance : FormatableVolume::Off
}
}
}
impl SwayStatusModuleInstance for PulseVolumeConfig {
fn make_runnable<'p>(&'p self,to_main : Box<dyn MsgModuleToMain + 'p>) -> (Box<dyn SwayStatusModuleRunnable + 'p>, Box<dyn MsgMainToModule + 'p>) {
let (runnable, sender_for_main) = crate::runnable::PulseVolumeRunnable::new(&self, to_main);
(Box::new(runnable), Box::new(sender_for_main))
}
}
///Helper trait for conversion from float to integer backing type for volume binning keys.
///Needed because Rust seems not to offer a trait that indicates "can be rounded from float"
///in the standard library. There are thir-party crates that do this, but using a full crate
///for a few lines of code sounds a bit excessive...
trait VolumeKeyBackingTypeFromFloat {
fn round_from_float(float : f32) -> Self;
}
macro_rules! impl_volume_key_backing_type_from_float_for {
($( $t:ty ), *) => {
$( impl VolumeKeyBackingTypeFromFloat for $t {
fn round_from_float(float : f32) -> $t { float.round() as $t }
} )*
}
}
///Metadata description for VolumeKeys. Basically a workaround for Rust's lack of
///constant generics. Having Ord as supertrait is because of the BTreeMap's trait
///bounds.
trait VolumeKeyBackingTypeMetadata : Ord {
type BackingType
: Ord
+ Add<Output = Self::BackingType>
+ Sub<Output = Self::BackingType>
+ Into<f32>
+ VolumeKeyBackingTypeFromFloat;
const MIN : Self::BackingType;
const MAX : Self::BackingType;
const FLOAT_MIN : f32;
const FLOAT_MAX : f32;
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
struct VolumeKeyVolume;
#[derive(PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
struct VolumeKeyBalance;
impl VolumeKeyBackingTypeMetadata for VolumeKeyVolume{
type BackingType = u8;
const MIN : Self::BackingType = 0;
const MAX : Self::BackingType = 100;
const FLOAT_MIN : f32 = 0.0;
const FLOAT_MAX : f32 = 1.0;
}
impl VolumeKeyBackingTypeMetadata for VolumeKeyBalance{
type BackingType = i8;
const MIN : Self::BackingType = -100;
const MAX : Self::BackingType = 100;
const FLOAT_MIN : f32 = -1.0;
const FLOAT_MAX : f32 = 1.0;
}
impl_volume_key_backing_type_from_float_for!(i8, u8);
#[derive(Debug,PartialEq,Eq,PartialOrd,Ord)]
struct VolumeKey<BackingType : VolumeKeyBackingTypeMetadata>(BackingType::BackingType);
impl<BackingType : VolumeKeyBackingTypeMetadata> VolumeKey<BackingType> {
fn match_float(float : f32) -> Self {
let x = (float - BackingType::FLOAT_MIN) / (BackingType::FLOAT_MAX - BackingType::FLOAT_MIN);
let cx = x.clamp(0.0,1.0);
let interval = BackingType::MAX - BackingType::MIN;
let offset = interval.into() * cx;
let result = BackingType::BackingType::round_from_float(offset) + BackingType::MIN;
Self(result)
}
}
impl<Metadata : VolumeKeyBackingTypeMetadata> Serialize for VolumeKey<Metadata> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S : Serializer
{
Err(serde::ser::Error::custom("Unimplemented"))
}
}
impl<'de, Metadata : VolumeKeyBackingTypeMetadata> Deserialize<'de> for VolumeKey<Metadata> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
Err(serde::de::Error::custom("Unimplemented"))
}
}
|