···55// Licensed under the BSD 3-Clause license. See LICENSE file in the project root
66// for full license information.
7788-use crate::message::InputCommandType;
88+use crate::{message::InputCommandType, util::range_serialize::*};
99use derive_builder::Builder;
1010use getset::{CopyGetters, Getters, MutGetters, Setters};
1111use serde::{ser::SerializeSeq, Deserialize, Serialize, Serializer};
···7272#[derive(
7373 Clone, Debug, Default, Getters, MutGetters, CopyGetters, Setters, Serialize, Deserialize,
7474)]
7575+#[serde(rename_all="PascalCase")]
7576pub struct DeviceFeature {
7677 // Index of the feature on the device. This was originally implicit as the position in the feature
7778 // array. We now make it explicit even though it's still just array position, because implicit
7879 // array positions have made life hell in so many different ways.
7980 #[getset(get_copy = "pub")]
8080- #[serde(rename = "FeatureIndex")]
8181 feature_index: u32,
8282 #[getset(get = "pub", get_mut = "pub(super)")]
8383- #[serde(default)]
8484- #[serde(rename = "FeatureDescription")]
8383+ #[serde(default, rename = "FeatureDescription")]
8584 description: String,
8685 // TODO Maybe make this its own object instead of a HashMap?
8786 #[getset(get = "pub")]
8887 #[serde(skip_serializing_if = "Option::is_none")]
8989- #[serde(rename = "Output")]
9088 output: Option<DeviceFeatureOutput>,
9189 #[getset(get = "pub")]
9290 #[serde(skip_serializing_if = "Option::is_none")]
9393- #[serde(rename = "Input")]
9491 input: Option<DeviceFeatureInput>,
9592}
9693···130127}
131128132129#[derive(Serialize, Deserialize, Clone, Debug, Getters)]
130130+#[serde(rename_all="PascalCase")]
133131pub struct DeviceFeatureOutputValueProperties {
134132 #[getset(get = "pub")]
135135- #[serde(rename = "Value")]
133133+ #[serde(serialize_with = "range_serialize")]
136134 value: RangeInclusive<i32>,
137135}
138136···156154}
157155158156#[derive(Serialize, Deserialize, Clone, Debug, Getters)]
157157+#[serde(rename_all="PascalCase")]
159158pub struct DeviceFeatureOutputPositionWithDurationProperties {
160159 #[getset(get = "pub")]
161161- #[serde(rename = "Position")]
160160+ #[serde(serialize_with = "range_serialize")]
162161 position: RangeInclusive<i32>,
163162 #[getset(get = "pub")]
164164- #[serde(rename = "Duration")]
163163+ #[serde(serialize_with = "range_serialize")]
165164 duration: RangeInclusive<i32>,
166165}
167166···187186#[derive(Clone, Debug, Getters, Setters, Default, Serialize, Deserialize, Builder)]
188187#[builder(setter(strip_option), default)]
189188#[getset(get = "pub")]
189189+#[serde(rename_all="PascalCase")]
190190pub struct DeviceFeatureOutput {
191191+ #[serde(skip_serializing_if="Option::is_none")]
191192 vibrate: Option<DeviceFeatureOutputValueProperties>,
193193+ #[serde(skip_serializing_if="Option::is_none")]
192194 rotate: Option<DeviceFeatureOutputValueProperties>,
195195+ #[serde(skip_serializing_if="Option::is_none")]
193196 rotate_with_direction: Option<DeviceFeatureOutputValueProperties>,
197197+ #[serde(skip_serializing_if="Option::is_none")]
194198 oscillate: Option<DeviceFeatureOutputValueProperties>,
199199+ #[serde(skip_serializing_if="Option::is_none")]
195200 constrict: Option<DeviceFeatureOutputValueProperties>,
201201+ #[serde(skip_serializing_if="Option::is_none")]
196202 heater: Option<DeviceFeatureOutputValueProperties>,
203203+ #[serde(skip_serializing_if="Option::is_none")]
197204 led: Option<DeviceFeatureOutputValueProperties>,
205205+ #[serde(skip_serializing_if="Option::is_none")]
198206 position: Option<DeviceFeatureOutputValueProperties>,
207207+ #[serde(skip_serializing_if="Option::is_none")]
199208 position_with_duration: Option<DeviceFeatureOutputPositionWithDurationProperties>,
209209+ #[serde(skip_serializing_if="Option::is_none")]
200210 spray: Option<DeviceFeatureOutputValueProperties>,
201211}
202212···237247#[derive(
238248 Clone, Debug, Default, PartialEq, Eq, Getters, MutGetters, Setters, Serialize, Deserialize,
239249)]
250250+#[serde(rename_all="PascalCase")]
240251pub struct DeviceFeatureInputProperties {
241252 #[getset(get = "pub", get_mut = "pub(super)")]
242242- #[serde(rename = "ValueRange")]
243253 #[serde(serialize_with = "range_sequence_serialize")]
244254 value_range: Vec<RangeInclusive<i32>>,
245255 #[getset(get = "pub")]
246246- #[serde(rename = "InputCommands")]
247256 input_commands: HashSet<InputCommandType>,
248257}
249258···263272#[derive(Clone, Debug, Getters, Setters, Default, Serialize, Deserialize, Builder)]
264273#[builder(setter(strip_option), default)]
265274#[getset(get = "pub")]
275275+#[serde(rename_all="PascalCase")]
266276pub struct DeviceFeatureInput {
277277+ #[serde(skip_serializing_if="Option::is_none")]
267278 battery: Option<DeviceFeatureInputProperties>,
279279+ #[serde(skip_serializing_if="Option::is_none")]
268280 rssi: Option<DeviceFeatureInputProperties>,
281281+ #[serde(skip_serializing_if="Option::is_none")]
269282 pressure: Option<DeviceFeatureInputProperties>,
283283+ #[serde(skip_serializing_if="Option::is_none")]
270284 button: Option<DeviceFeatureInputProperties>,
271285}
272286
+1
crates/buttplug_core/src/util/mod.rs
···1212pub mod future;
1313pub mod json;
1414pub mod stream;
1515+pub mod range_serialize;
15161617#[cfg(not(feature = "wasm"))]
1718pub use tokio::time::sleep;
···111111 }
112112113113 pub fn calculate_scaled_float(&self, value: f64) -> Result<i32, ButtplugDeviceConfigError> {
114114- if value > 1.0 || value < 1.0 {
114114+ if value > 1.0 || value < 0.0 {
115115 Err(ButtplugDeviceConfigError::InvalidFloatConversion(value))
116116 } else {
117117 let value = if value < 0.000001 { 0f64 } else { value };
118118- self.calculate_scaled_value((self.value.step_count() as f64 * value) as i32)
118118+ self.calculate_scaled_value((self.value.step_count() as f64 * value).ceil() as i32)
119119 }
120120 }
121121···168168 }
169169170170 pub fn calculate_scaled_float(&self, value: f64) -> Result<i32, ButtplugDeviceConfigError> {
171171- self
172172- .calculate_scaled_value((self.position.step_count() as f64 * value) as u32)
173173- .map(|x| x as i32)
171171+ if value > 1.0 || value < 0.0 {
172172+ Err(ButtplugDeviceConfigError::InvalidFloatConversion(value))
173173+ } else {
174174+ self
175175+ .calculate_scaled_value((self.position.step_count() as f64 * value).ceil() as u32)
176176+ .map(|x| x as i32)
177177+ }
174178 }
175179176180 // We'll get a number from 0-x here. We'll need to calculate it with in the range we have.