Buttplug sex toy control library

chore: Fix issues causing protocol tests to fail

+238 -144
+2 -2
Cargo.toml
··· 16 16 "crates/buttplug_server_hwmgr_xinput", 17 17 "crates/buttplug_tests", 18 18 "crates/buttplug_transport_websocket_tungstenite", 19 - "crates/examples", 20 - "crates/intiface_engine", 19 + #"crates/examples", 20 + #"crates/intiface_engine", 21 21 ] 22 22 23 23 [profile.release]
+25 -11
crates/buttplug_core/src/message/device_feature.rs
··· 5 5 // Licensed under the BSD 3-Clause license. See LICENSE file in the project root 6 6 // for full license information. 7 7 8 - use crate::message::InputCommandType; 8 + use crate::{message::InputCommandType, util::range_serialize::*}; 9 9 use derive_builder::Builder; 10 10 use getset::{CopyGetters, Getters, MutGetters, Setters}; 11 11 use serde::{ser::SerializeSeq, Deserialize, Serialize, Serializer}; ··· 72 72 #[derive( 73 73 Clone, Debug, Default, Getters, MutGetters, CopyGetters, Setters, Serialize, Deserialize, 74 74 )] 75 + #[serde(rename_all="PascalCase")] 75 76 pub struct DeviceFeature { 76 77 // Index of the feature on the device. This was originally implicit as the position in the feature 77 78 // array. We now make it explicit even though it's still just array position, because implicit 78 79 // array positions have made life hell in so many different ways. 79 80 #[getset(get_copy = "pub")] 80 - #[serde(rename = "FeatureIndex")] 81 81 feature_index: u32, 82 82 #[getset(get = "pub", get_mut = "pub(super)")] 83 - #[serde(default)] 84 - #[serde(rename = "FeatureDescription")] 83 + #[serde(default, rename = "FeatureDescription")] 85 84 description: String, 86 85 // TODO Maybe make this its own object instead of a HashMap? 87 86 #[getset(get = "pub")] 88 87 #[serde(skip_serializing_if = "Option::is_none")] 89 - #[serde(rename = "Output")] 90 88 output: Option<DeviceFeatureOutput>, 91 89 #[getset(get = "pub")] 92 90 #[serde(skip_serializing_if = "Option::is_none")] 93 - #[serde(rename = "Input")] 94 91 input: Option<DeviceFeatureInput>, 95 92 } 96 93 ··· 130 127 } 131 128 132 129 #[derive(Serialize, Deserialize, Clone, Debug, Getters)] 130 + #[serde(rename_all="PascalCase")] 133 131 pub struct DeviceFeatureOutputValueProperties { 134 132 #[getset(get = "pub")] 135 - #[serde(rename = "Value")] 133 + #[serde(serialize_with = "range_serialize")] 136 134 value: RangeInclusive<i32>, 137 135 } 138 136 ··· 156 154 } 157 155 158 156 #[derive(Serialize, Deserialize, Clone, Debug, Getters)] 157 + #[serde(rename_all="PascalCase")] 159 158 pub struct DeviceFeatureOutputPositionWithDurationProperties { 160 159 #[getset(get = "pub")] 161 - #[serde(rename = "Position")] 160 + #[serde(serialize_with = "range_serialize")] 162 161 position: RangeInclusive<i32>, 163 162 #[getset(get = "pub")] 164 - #[serde(rename = "Duration")] 163 + #[serde(serialize_with = "range_serialize")] 165 164 duration: RangeInclusive<i32>, 166 165 } 167 166 ··· 187 186 #[derive(Clone, Debug, Getters, Setters, Default, Serialize, Deserialize, Builder)] 188 187 #[builder(setter(strip_option), default)] 189 188 #[getset(get = "pub")] 189 + #[serde(rename_all="PascalCase")] 190 190 pub struct DeviceFeatureOutput { 191 + #[serde(skip_serializing_if="Option::is_none")] 191 192 vibrate: Option<DeviceFeatureOutputValueProperties>, 193 + #[serde(skip_serializing_if="Option::is_none")] 192 194 rotate: Option<DeviceFeatureOutputValueProperties>, 195 + #[serde(skip_serializing_if="Option::is_none")] 193 196 rotate_with_direction: Option<DeviceFeatureOutputValueProperties>, 197 + #[serde(skip_serializing_if="Option::is_none")] 194 198 oscillate: Option<DeviceFeatureOutputValueProperties>, 199 + #[serde(skip_serializing_if="Option::is_none")] 195 200 constrict: Option<DeviceFeatureOutputValueProperties>, 201 + #[serde(skip_serializing_if="Option::is_none")] 196 202 heater: Option<DeviceFeatureOutputValueProperties>, 203 + #[serde(skip_serializing_if="Option::is_none")] 197 204 led: Option<DeviceFeatureOutputValueProperties>, 205 + #[serde(skip_serializing_if="Option::is_none")] 198 206 position: Option<DeviceFeatureOutputValueProperties>, 207 + #[serde(skip_serializing_if="Option::is_none")] 199 208 position_with_duration: Option<DeviceFeatureOutputPositionWithDurationProperties>, 209 + #[serde(skip_serializing_if="Option::is_none")] 200 210 spray: Option<DeviceFeatureOutputValueProperties>, 201 211 } 202 212 ··· 237 247 #[derive( 238 248 Clone, Debug, Default, PartialEq, Eq, Getters, MutGetters, Setters, Serialize, Deserialize, 239 249 )] 250 + #[serde(rename_all="PascalCase")] 240 251 pub struct DeviceFeatureInputProperties { 241 252 #[getset(get = "pub", get_mut = "pub(super)")] 242 - #[serde(rename = "ValueRange")] 243 253 #[serde(serialize_with = "range_sequence_serialize")] 244 254 value_range: Vec<RangeInclusive<i32>>, 245 255 #[getset(get = "pub")] 246 - #[serde(rename = "InputCommands")] 247 256 input_commands: HashSet<InputCommandType>, 248 257 } 249 258 ··· 263 272 #[derive(Clone, Debug, Getters, Setters, Default, Serialize, Deserialize, Builder)] 264 273 #[builder(setter(strip_option), default)] 265 274 #[getset(get = "pub")] 275 + #[serde(rename_all="PascalCase")] 266 276 pub struct DeviceFeatureInput { 277 + #[serde(skip_serializing_if="Option::is_none")] 267 278 battery: Option<DeviceFeatureInputProperties>, 279 + #[serde(skip_serializing_if="Option::is_none")] 268 280 rssi: Option<DeviceFeatureInputProperties>, 281 + #[serde(skip_serializing_if="Option::is_none")] 269 282 pressure: Option<DeviceFeatureInputProperties>, 283 + #[serde(skip_serializing_if="Option::is_none")] 270 284 button: Option<DeviceFeatureInputProperties>, 271 285 } 272 286
+1
crates/buttplug_core/src/util/mod.rs
··· 12 12 pub mod future; 13 13 pub mod json; 14 14 pub mod stream; 15 + pub mod range_serialize; 15 16 16 17 #[cfg(not(feature = "wasm"))] 17 18 pub use tokio::time::sleep;
+27
crates/buttplug_core/src/util/range_serialize.rs
··· 1 + use std::ops::RangeInclusive; 2 + 3 + use serde::{Serializer, ser::SerializeSeq}; 4 + 5 + pub fn range_serialize<S>(range: &RangeInclusive<i32>, serializer: S) -> Result<S::Ok, S::Error> 6 + where 7 + S: Serializer, 8 + { 9 + let mut seq = serializer.serialize_seq(Some(2))?; 10 + seq.serialize_element(&range.start())?; 11 + seq.serialize_element(&range.end())?; 12 + seq.end() 13 + } 14 + 15 + pub fn range_sequence_serialize<S>( 16 + range_vec: &Vec<RangeInclusive<i32>>, 17 + serializer: S, 18 + ) -> Result<S::Ok, S::Error> 19 + where 20 + S: Serializer, 21 + { 22 + let mut seq = serializer.serialize_seq(Some(range_vec.len()))?; 23 + for range in range_vec { 24 + seq.serialize_element(&vec![*range.start(), *range.end()])?; 25 + } 26 + seq.end() 27 + }
+1 -1
crates/buttplug_server/src/device/server_device_manager_event_loop.rs
··· 247 247 } 248 248 }, 249 249 Err(e) => { 250 - error!("Device errored while trying to connect: {}", e); 250 + error!("Device errored while trying to connect: {:?}", e); 251 251 } 252 252 } 253 253 connecting_devices.remove(&address);
+4
crates/buttplug_server/src/message/v3/client_device_message_attributes.rs
··· 285 285 .spray() 286 286 .as_ref() 287 287 .map(|x| create_actuator(OutputType::Spray, x)); 288 + output_map 289 + .vibrate() 290 + .as_ref() 291 + .map(|x| create_actuator(OutputType::Vibrate, x)); 288 292 } 289 293 actuator_vec 290 294 })
+43 -15
crates/buttplug_server/src/message/v3/server_device_message_attributes.rs
··· 72 72 }; 73 73 // TODO oh come on just make a fucking iterator here. At least, once we figure out the 74 74 // unifying trait we can use to make an iterator on this. 75 - output_map.constrict().as_ref().map(|attr| create_attribute(OutputType::Constrict, attr.value().step_count())); 76 - output_map.oscillate().as_ref().map(|attr| create_attribute(OutputType::Oscillate, attr.value().step_count())); 77 - output_map.position().as_ref().map(|attr| create_attribute(OutputType::Position, attr.position().step_count())); 78 - output_map.rotate().as_ref().map(|attr| create_attribute(OutputType::Rotate, attr.value().step_count())); 75 + output_map 76 + .constrict() 77 + .as_ref() 78 + .map(|attr| create_attribute(OutputType::Constrict, attr.value().step_count())); 79 + output_map 80 + .oscillate() 81 + .as_ref() 82 + .map(|attr| create_attribute(OutputType::Oscillate, attr.value().step_count())); 83 + output_map 84 + .position() 85 + .as_ref() 86 + .map(|attr| create_attribute(OutputType::Position, attr.position().step_count())); 87 + output_map 88 + .rotate() 89 + .as_ref() 90 + .map(|attr| create_attribute(OutputType::Rotate, attr.value().step_count())); 91 + output_map 92 + .heater() 93 + .as_ref() 94 + .map(|attr| create_attribute(OutputType::Heater, attr.value().step_count())); 95 + output_map 96 + .led() 97 + .as_ref() 98 + .map(|attr| create_attribute(OutputType::Led, attr.value().step_count())); 99 + output_map 100 + .vibrate() 101 + .as_ref() 102 + .map(|attr| create_attribute(OutputType::Vibrate, attr.value().step_count())); 103 + output_map 104 + .spray() 105 + .as_ref() 106 + .map(|attr| create_attribute(OutputType::Spray, attr.value().step_count())); 79 107 } 80 108 actuator_vec 81 109 }) ··· 111 139 let mut actuator_vec = vec![]; 112 140 if let Some(output_map) = feature.output() { 113 141 if let Some(actuator) = output_map.position_with_duration() { 114 - let actuator_type = OutputType::Position; 115 - let step_count = actuator.position().step_count(); 116 - let attrs = ServerGenericDeviceMessageAttributesV3 { 117 - feature_descriptor: feature.description().to_owned(), 118 - actuator_type, 119 - step_count, 120 - feature: feature.clone(), 121 - index: 0, 122 - }; 123 - actuator_vec.push(attrs) 124 - } 142 + let actuator_type = OutputType::Position; 143 + let step_count = actuator.position().step_count(); 144 + let attrs = ServerGenericDeviceMessageAttributesV3 { 145 + feature_descriptor: feature.description().to_owned(), 146 + actuator_type, 147 + step_count, 148 + feature: feature.clone(), 149 + index: 0, 150 + }; 151 + actuator_vec.push(attrs) 125 152 } 153 + } 126 154 actuator_vec 127 155 }) 128 156 .collect();
+8 -9
crates/buttplug_server/src/message/v4/checked_output_vec_cmd.rs
··· 220 220 )); 221 221 } 222 222 for cmd in msg.scalars() { 223 - let scalar_attrs = attrs 223 + let scalar_attrs = if let Some(a) = attrs 224 224 .attrs_v3() 225 - .scalar_cmd() 226 - .as_ref() 227 - .ok_or(ButtplugError::from( 228 - ButtplugDeviceError::MessageNotSupported( 229 - ButtplugDeviceMessageNameV3::ScalarCmd.to_string(), 230 - ), 231 - ))?; 225 + .scalar_cmd() { 226 + a 227 + } else { 228 + continue; 229 + }; 232 230 let feature = scalar_attrs 233 231 .get(cmd.index() as usize) 234 232 .ok_or(ButtplugError::from( ··· 250 248 ))?; 251 249 let output_value = output 252 250 .calculate_from_float(cmd.actuator_type(), cmd.scalar()) 253 - .map_err(|_| { 251 + .map_err(|e| { 252 + error!("{:?}", e); 254 253 ButtplugError::from(ButtplugDeviceError::DeviceNoActuatorError( 255 254 "ScalarCmdV3".to_owned(), 256 255 ))
+7 -7
crates/buttplug_server_device_config/build-config/buttplug-device-config-v4.json
··· 1 1 { 2 2 "version": { 3 3 "major": 4, 4 - "minor": 64 4 + "minor": 65 5 5 }, 6 6 "protocols": { 7 7 "activejoy": { ··· 18829 18829 "Bach smart" 18830 18830 ], 18831 18831 "name": "Vorze Bach", 18832 - "protocol-variant": "vorze-sa-vibrator" 18832 + "protocol_variant": "vorze-sa-vibrator" 18833 18833 }, 18834 18834 { 18835 18835 "features": [ ··· 18850 18850 "ROCKET" 18851 18851 ], 18852 18852 "name": "Adult Festa Rocket", 18853 - "protocol-variant": "vorze-sa-vibrator" 18853 + "protocol_variant": "vorze-sa-vibrator" 18854 18854 }, 18855 18855 { 18856 18856 "features": [ ··· 18871 18871 "CycSA" 18872 18872 ], 18873 18873 "name": "Vorze A10 Cyclone SA", 18874 - "protocol-variant": "vorze-sa-single-rotator" 18874 + "protocol_variant": "vorze-sa-single-rotator" 18875 18875 }, 18876 18876 { 18877 18877 "features": [ ··· 18892 18892 "UFOSA" 18893 18893 ], 18894 18894 "name": "Vorze UFO SA", 18895 - "protocol-variant": "vorze-sa-single-rotator" 18895 + "protocol_variant": "vorze-sa-single-rotator" 18896 18896 }, 18897 18897 { 18898 18898 "features": [ ··· 18924 18924 "UFO-TW" 18925 18925 ], 18926 18926 "name": "Vorze UFO TW", 18927 - "protocol-variant": "vorze-sa-dual-rotator" 18927 + "protocol_variant": "vorze-sa-dual-rotator" 18928 18928 }, 18929 18929 { 18930 18930 "features": [ ··· 18949 18949 "VorzePiston" 18950 18950 ], 18951 18951 "name": "Vorze Piston", 18952 - "protocol-variant": "vorze-sa-piston" 18952 + "protocol_variant": "vorze-sa-piston" 18953 18953 } 18954 18954 ], 18955 18955 "defaults": {
+108 -92
crates/buttplug_server_device_config/src/device_config_file/feature.rs
··· 1 1 use std::{collections::HashSet, ops::RangeInclusive}; 2 2 3 - use buttplug_core::message::InputCommandType; 3 + use crate::{ 4 + ButtplugDeviceConfigError, 5 + RangeWithLimit, 6 + ServerDeviceFeature, 7 + ServerDeviceFeatureInput, 8 + ServerDeviceFeatureInputProperties, 9 + ServerDeviceFeatureOutput, 10 + ServerDeviceFeatureOutputPositionProperties, 11 + ServerDeviceFeatureOutputPositionWithDurationProperties, 12 + ServerDeviceFeatureOutputValueProperties, 13 + }; 14 + use buttplug_core::{message::InputCommandType, util::range_serialize::range_sequence_serialize}; 4 15 use getset::{CopyGetters, Getters, MutGetters, Setters}; 5 - use serde::{Deserialize, Serialize, Serializer, ser::{self, SerializeSeq}}; 16 + use serde::{Deserialize, Serialize}; 6 17 use uuid::Uuid; 7 - use crate::{ButtplugDeviceConfigError, RangeWithLimit, ServerDeviceFeature, ServerDeviceFeatureInput, ServerDeviceFeatureInputProperties, ServerDeviceFeatureOutput, ServerDeviceFeatureOutputPositionProperties, ServerDeviceFeatureOutputPositionWithDurationProperties, ServerDeviceFeatureOutputValueProperties}; 8 - 9 - fn range_serialize<S>(range: &Option<RangeInclusive<u32>>, serializer: S) -> Result<S::Ok, S::Error> 10 - where 11 - S: Serializer, 12 - { 13 - if let Some(range) = range { 14 - let mut seq = serializer.serialize_seq(Some(2))?; 15 - seq.serialize_element(&range.start())?; 16 - seq.serialize_element(&range.end())?; 17 - seq.end() 18 - } else { 19 - Err(ser::Error::custom( 20 - "shouldn't be serializing if range is None", 21 - )) 22 - } 23 - } 24 - 25 - fn range_sequence_serialize<S>( 26 - range_vec: &Vec<RangeInclusive<i32>>, 27 - serializer: S, 28 - ) -> Result<S::Ok, S::Error> 29 - where 30 - S: Serializer, 31 - { 32 - let mut seq = serializer.serialize_seq(Some(range_vec.len()))?; 33 - for range in range_vec { 34 - seq.serialize_element(&vec![*range.start(), *range.end()])?; 35 - } 36 - seq.end() 37 - } 38 18 39 19 #[derive(Serialize, Deserialize, Clone, Debug)] 40 20 struct BaseDeviceFeatureOutputValueProperties { 41 - value: RangeInclusive<i32> 21 + value: RangeInclusive<i32>, 42 22 } 43 23 44 24 impl Into<ServerDeviceFeatureOutputValueProperties> for BaseDeviceFeatureOutputValueProperties { ··· 49 29 50 30 #[derive(Serialize, Deserialize, Clone, Debug)] 51 31 struct BaseDeviceFeatureOutputPositionProperties { 52 - value: RangeInclusive<i32> 32 + value: RangeInclusive<i32>, 53 33 } 54 34 55 - impl Into<ServerDeviceFeatureOutputPositionProperties> for BaseDeviceFeatureOutputPositionProperties { 35 + impl Into<ServerDeviceFeatureOutputPositionProperties> 36 + for BaseDeviceFeatureOutputPositionProperties 37 + { 56 38 fn into(self) -> ServerDeviceFeatureOutputPositionProperties { 57 39 ServerDeviceFeatureOutputPositionProperties::new(&self.value.into(), false, false) 58 40 } ··· 64 46 duration: RangeInclusive<i32>, 65 47 } 66 48 67 - impl Into<ServerDeviceFeatureOutputPositionWithDurationProperties> for BaseDeviceFeatureOutputPositionWithDurationProperties { 49 + impl Into<ServerDeviceFeatureOutputPositionWithDurationProperties> 50 + for BaseDeviceFeatureOutputPositionWithDurationProperties 51 + { 68 52 fn into(self) -> ServerDeviceFeatureOutputPositionWithDurationProperties { 69 - ServerDeviceFeatureOutputPositionWithDurationProperties::new(&self.position.into(), &self.duration.into(), false, false) 53 + ServerDeviceFeatureOutputPositionWithDurationProperties::new( 54 + &self.position.into(), 55 + &self.duration.into(), 56 + false, 57 + false, 58 + ) 70 59 } 71 60 } 72 61 73 62 #[derive(Serialize, Deserialize, Clone, Debug)] 74 63 struct BaseDeviceFeatureOutput { 75 - #[serde(skip_serializing_if="Option::is_none")] 64 + #[serde(skip_serializing_if = "Option::is_none")] 76 65 vibrate: Option<BaseDeviceFeatureOutputValueProperties>, 77 - #[serde(skip_serializing_if="Option::is_none")] 66 + #[serde(skip_serializing_if = "Option::is_none")] 78 67 rotate: Option<BaseDeviceFeatureOutputValueProperties>, 79 - #[serde(skip_serializing_if="Option::is_none")] 68 + #[serde(skip_serializing_if = "Option::is_none")] 80 69 rotate_with_direction: Option<BaseDeviceFeatureOutputValueProperties>, 81 - #[serde(skip_serializing_if="Option::is_none")] 70 + #[serde(skip_serializing_if = "Option::is_none")] 82 71 oscillate: Option<BaseDeviceFeatureOutputValueProperties>, 83 - #[serde(skip_serializing_if="Option::is_none")] 72 + #[serde(skip_serializing_if = "Option::is_none")] 84 73 constrict: Option<BaseDeviceFeatureOutputValueProperties>, 85 - #[serde(skip_serializing_if="Option::is_none")] 74 + #[serde(skip_serializing_if = "Option::is_none")] 86 75 heater: Option<BaseDeviceFeatureOutputValueProperties>, 87 - #[serde(skip_serializing_if="Option::is_none")] 76 + #[serde(skip_serializing_if = "Option::is_none")] 88 77 led: Option<BaseDeviceFeatureOutputValueProperties>, 89 - #[serde(skip_serializing_if="Option::is_none")] 78 + #[serde(skip_serializing_if = "Option::is_none")] 90 79 position: Option<BaseDeviceFeatureOutputPositionProperties>, 91 - #[serde(skip_serializing_if="Option::is_none")] 80 + #[serde(skip_serializing_if = "Option::is_none")] 92 81 position_with_duration: Option<BaseDeviceFeatureOutputPositionWithDurationProperties>, 93 - #[serde(skip_serializing_if="Option::is_none")] 82 + #[serde(skip_serializing_if = "Option::is_none")] 94 83 spray: Option<BaseDeviceFeatureOutputValueProperties>, 95 84 } 96 85 ··· 127 116 if let Some(spray) = self.spray { 128 117 output.set_spray(Some(spray.into())); 129 118 } 130 - 131 119 output 132 120 } 133 121 } 134 122 135 123 #[derive(Serialize, Deserialize, Clone, Debug)] 136 124 struct UserDeviceFeatureOutputValueProperties { 137 - #[serde(skip_serializing_if="Option::is_none")] 125 + #[serde(skip_serializing_if = "Option::is_none")] 138 126 value: Option<RangeInclusive<u32>>, 139 127 #[serde(default)] 140 128 disabled: bool, 141 129 } 142 130 143 131 impl UserDeviceFeatureOutputValueProperties { 144 - pub fn with_base_properties(&self, base: &ServerDeviceFeatureOutputValueProperties) -> Result<ServerDeviceFeatureOutputValueProperties, ButtplugDeviceConfigError> { 132 + pub fn with_base_properties( 133 + &self, 134 + base: &ServerDeviceFeatureOutputValueProperties, 135 + ) -> Result<ServerDeviceFeatureOutputValueProperties, ButtplugDeviceConfigError> { 145 136 let range = RangeWithLimit::try_new(base.value().base(), &self.value)?; 146 - Ok(ServerDeviceFeatureOutputValueProperties::new(&range, self.disabled)) 137 + Ok(ServerDeviceFeatureOutputValueProperties::new( 138 + &range, 139 + self.disabled, 140 + )) 147 141 } 148 142 } 149 143 150 144 #[derive(Serialize, Deserialize, Clone, Debug)] 151 145 struct UserDeviceFeatureOutputPositionProperties { 152 - #[serde(skip_serializing_if="Option::is_none")] 146 + #[serde(skip_serializing_if = "Option::is_none")] 153 147 value: Option<RangeInclusive<u32>>, 154 148 #[serde(default)] 155 149 disabled: bool, 156 150 #[serde(default)] 157 - reverse: bool 151 + reverse: bool, 158 152 } 159 153 160 154 impl UserDeviceFeatureOutputPositionProperties { 161 - pub fn with_base_properties(&self, base: &ServerDeviceFeatureOutputPositionProperties) -> Result<ServerDeviceFeatureOutputPositionProperties, ButtplugDeviceConfigError> { 155 + pub fn with_base_properties( 156 + &self, 157 + base: &ServerDeviceFeatureOutputPositionProperties, 158 + ) -> Result<ServerDeviceFeatureOutputPositionProperties, ButtplugDeviceConfigError> { 162 159 let value = RangeWithLimit::try_new(base.position().base(), &self.value)?; 163 - Ok(ServerDeviceFeatureOutputPositionProperties::new(&value, self.disabled, self.reverse)) 160 + Ok(ServerDeviceFeatureOutputPositionProperties::new( 161 + &value, 162 + self.disabled, 163 + self.reverse, 164 + )) 164 165 } 165 166 } 166 167 167 168 #[derive(Serialize, Deserialize, Clone, Debug)] 168 169 struct UserDeviceFeatureOutputPositionWithDurationProperties { 169 - #[serde(skip_serializing_if="Option::is_none")] 170 + #[serde(skip_serializing_if = "Option::is_none")] 170 171 position: Option<RangeInclusive<u32>>, 171 - #[serde(skip_serializing_if="Option::is_none")] 172 + #[serde(skip_serializing_if = "Option::is_none")] 172 173 duration: Option<RangeInclusive<u32>>, 173 174 #[serde(default)] 174 175 disabled: bool, 175 176 #[serde(default)] 176 - reverse: bool 177 + reverse: bool, 177 178 } 178 179 179 180 impl UserDeviceFeatureOutputPositionWithDurationProperties { 180 - pub fn with_base_properties(&self, base: &ServerDeviceFeatureOutputPositionWithDurationProperties) -> Result<ServerDeviceFeatureOutputPositionWithDurationProperties, ButtplugDeviceConfigError> { 181 + pub fn with_base_properties( 182 + &self, 183 + base: &ServerDeviceFeatureOutputPositionWithDurationProperties, 184 + ) -> Result<ServerDeviceFeatureOutputPositionWithDurationProperties, ButtplugDeviceConfigError> 185 + { 181 186 let position = RangeWithLimit::try_new(base.position().base(), &self.position)?; 182 187 let duration = RangeWithLimit::try_new(base.duration().base(), &self.duration)?; 183 - Ok(ServerDeviceFeatureOutputPositionWithDurationProperties::new(&position, &duration, self.disabled, self.reverse)) 188 + Ok( 189 + ServerDeviceFeatureOutputPositionWithDurationProperties::new( 190 + &position, 191 + &duration, 192 + self.disabled, 193 + self.reverse, 194 + ), 195 + ) 184 196 } 185 197 } 186 198 #[derive(Serialize, Deserialize, Clone, Debug)] 187 199 struct UserDeviceFeatureOutput { 188 - #[serde(skip_serializing_if="Option::is_none")] 200 + #[serde(skip_serializing_if = "Option::is_none")] 189 201 vibrate: Option<UserDeviceFeatureOutputValueProperties>, 190 - #[serde(skip_serializing_if="Option::is_none")] 202 + #[serde(skip_serializing_if = "Option::is_none")] 191 203 rotate: Option<UserDeviceFeatureOutputValueProperties>, 192 - #[serde(skip_serializing_if="Option::is_none")] 204 + #[serde(skip_serializing_if = "Option::is_none")] 193 205 rotate_with_direction: Option<UserDeviceFeatureOutputValueProperties>, 194 - #[serde(skip_serializing_if="Option::is_none")] 206 + #[serde(skip_serializing_if = "Option::is_none")] 195 207 oscillate: Option<UserDeviceFeatureOutputValueProperties>, 196 - #[serde(skip_serializing_if="Option::is_none")] 208 + #[serde(skip_serializing_if = "Option::is_none")] 197 209 constrict: Option<UserDeviceFeatureOutputValueProperties>, 198 - #[serde(skip_serializing_if="Option::is_none")] 210 + #[serde(skip_serializing_if = "Option::is_none")] 199 211 heater: Option<UserDeviceFeatureOutputValueProperties>, 200 - #[serde(skip_serializing_if="Option::is_none")] 212 + #[serde(skip_serializing_if = "Option::is_none")] 201 213 led: Option<UserDeviceFeatureOutputValueProperties>, 202 - #[serde(skip_serializing_if="Option::is_none")] 214 + #[serde(skip_serializing_if = "Option::is_none")] 203 215 position: Option<UserDeviceFeatureOutputPositionProperties>, 204 - #[serde(skip_serializing_if="Option::is_none")] 216 + #[serde(skip_serializing_if = "Option::is_none")] 205 217 position_with_duration: Option<UserDeviceFeatureOutputPositionWithDurationProperties>, 206 - #[serde(skip_serializing_if="Option::is_none")] 218 + #[serde(skip_serializing_if = "Option::is_none")] 207 219 spray: Option<UserDeviceFeatureOutputValueProperties>, 208 220 } 209 221 210 222 impl UserDeviceFeatureOutput { 211 - pub fn with_base_output(&self, base_output: &ServerDeviceFeatureOutput) -> Result<ServerDeviceFeatureOutput, ButtplugDeviceConfigError> { 223 + pub fn with_base_output( 224 + &self, 225 + base_output: &ServerDeviceFeatureOutput, 226 + ) -> Result<ServerDeviceFeatureOutput, ButtplugDeviceConfigError> { 212 227 let mut output = ServerDeviceFeatureOutput::default(); 213 228 if let Some(base_vibrate) = base_output.vibrate() { 214 229 if let Some(user_vibrate) = &self.vibrate { ··· 285 300 #[serde(serialize_with = "range_sequence_serialize")] 286 301 value_range: Vec<RangeInclusive<i32>>, 287 302 #[getset(get = "pub")] 288 - input_commands: HashSet<InputCommandType> 303 + input_commands: HashSet<InputCommandType>, 289 304 } 290 305 291 306 impl DeviceFeatureInputProperties { ··· 306 321 } 307 322 } 308 323 309 - #[derive( 310 - Clone, Debug, Default, Getters, Serialize, Deserialize, 311 - )] 324 + #[derive(Clone, Debug, Default, Getters, Serialize, Deserialize)] 312 325 #[getset(get = "pub")] 313 326 pub struct DeviceFeatureInput { 314 327 battery: Option<DeviceFeatureInputProperties>, 315 328 rssi: Option<DeviceFeatureInputProperties>, 316 329 pressure: Option<DeviceFeatureInputProperties>, 317 - button: Option<DeviceFeatureInputProperties> 330 + button: Option<DeviceFeatureInputProperties>, 318 331 } 319 332 320 333 impl Into<ServerDeviceFeatureInput> for DeviceFeatureInput { ··· 336 349 } 337 350 } 338 351 339 - #[derive( 340 - Clone, Debug, Default, Getters, Serialize, Deserialize, CopyGetters, 341 - )] 352 + #[derive(Clone, Debug, Default, Getters, Serialize, Deserialize, CopyGetters)] 342 353 pub struct ConfigBaseDeviceFeature { 343 354 #[getset(get = "pub")] 344 355 #[serde(default)] ··· 352 363 #[getset(get_copy = "pub")] 353 364 id: Uuid, 354 365 #[getset(get = "pub")] 355 - #[serde( 356 - skip_serializing_if = "BaseFeatureSettings::is_none", 357 - default 358 - )] 366 + #[serde(skip_serializing_if = "BaseFeatureSettings::is_none", default)] 359 367 feature_settings: BaseFeatureSettings, 360 368 } 361 369 ··· 378 386 None, 379 387 self.feature_settings.alt_protocol_index, 380 388 &output, 381 - &input 382 - ) 389 + &input, 390 + ) 383 391 } 384 392 } 385 393 386 - #[derive( 387 - Clone, Debug, Default, Getters, Serialize, Deserialize, CopyGetters, 388 - )] 394 + #[derive(Clone, Debug, Default, Getters, Serialize, Deserialize, CopyGetters)] 389 395 pub struct ConfigUserDeviceFeature { 390 396 #[getset(get_copy = "pub")] 391 397 id: Uuid, ··· 393 399 base_id: Uuid, 394 400 #[getset(get = "pub")] 395 401 #[serde(rename = "output", skip_serializing_if = "Option::is_none")] 396 - output: Option<UserDeviceFeatureOutput> 402 + output: Option<UserDeviceFeatureOutput>, 397 403 } 398 404 399 405 impl ConfigUserDeviceFeature { 400 - pub fn with_base_feature(&self, base_feature: &ServerDeviceFeature) -> Result<ServerDeviceFeature, ButtplugDeviceConfigError> { 406 + pub fn with_base_feature( 407 + &self, 408 + base_feature: &ServerDeviceFeature, 409 + ) -> Result<ServerDeviceFeature, ButtplugDeviceConfigError> { 401 410 let output = if let Some(o) = &self.output { 402 411 if let Some(base) = base_feature.output() { 403 412 Some(o.with_base_output(&base)?) ··· 407 416 } else { 408 417 None 409 418 }; 410 - Ok(ServerDeviceFeature::new(&base_feature.description(), self.id, Some(self.base_id), base_feature.alt_protocol_index(), &output, base_feature.input())) 419 + Ok(ServerDeviceFeature::new( 420 + &base_feature.description(), 421 + self.id, 422 + Some(self.base_id), 423 + base_feature.alt_protocol_index(), 424 + &output, 425 + base_feature.input(), 426 + )) 411 427 } 412 428 } 413 429
+3 -1
crates/buttplug_server_device_config/src/device_config_file/mod.rs
··· 228 228 .config() 229 229 .build_from_base_definition(base_config) 230 230 { 231 - dcm_builder.user_device_definition(user_device_config_pair.identifier(), &user_config); 231 + if let Err(e) = dcm_builder.user_device_definition(user_device_config_pair.identifier(), &user_config) { 232 + error!("Device definition not valid, skipping:\n{:?}\n{:?}", e, user_config) 233 + } 232 234 } 233 235 } else { 234 236 error!(
-1
crates/buttplug_server_device_config/src/device_definitions.rs
··· 55 55 let mut value = value.clone(); 56 56 value.base_id = Some(value.id); 57 57 value.id = id; 58 - value.features = vec!(); 59 58 ServerDeviceDefinitionBuilder { def: value } 60 59 } 61 60
+9 -5
crates/buttplug_server_device_config/src/server_device_feature.rs
··· 111 111 } 112 112 113 113 pub fn calculate_scaled_float(&self, value: f64) -> Result<i32, ButtplugDeviceConfigError> { 114 - if value > 1.0 || value < 1.0 { 114 + if value > 1.0 || value < 0.0 { 115 115 Err(ButtplugDeviceConfigError::InvalidFloatConversion(value)) 116 116 } else { 117 117 let value = if value < 0.000001 { 0f64 } else { value }; 118 - self.calculate_scaled_value((self.value.step_count() as f64 * value) as i32) 118 + self.calculate_scaled_value((self.value.step_count() as f64 * value).ceil() as i32) 119 119 } 120 120 } 121 121 ··· 168 168 } 169 169 170 170 pub fn calculate_scaled_float(&self, value: f64) -> Result<i32, ButtplugDeviceConfigError> { 171 - self 172 - .calculate_scaled_value((self.position.step_count() as f64 * value) as u32) 173 - .map(|x| x as i32) 171 + if value > 1.0 || value < 0.0 { 172 + Err(ButtplugDeviceConfigError::InvalidFloatConversion(value)) 173 + } else { 174 + self 175 + .calculate_scaled_value((self.position.step_count() as f64 * value).ceil() as u32) 176 + .map(|x| x as i32) 177 + } 174 178 } 175 179 176 180 // We'll get a number from 0-x here. We'll need to calculate it with in the range we have.