Buttplug sex toy control library
1// Buttplug Rust Source Code File - See https://buttplug.io for more info.
2//
3// Copyright 2016-2024 Nonpolynomial Labs LLC. All rights reserved.
4//
5// Licensed under the BSD 3-Clause license. See LICENSE file in the project root
6// for full license information.
7
8use crate::message::{
9 v1::{
10 ClientDeviceMessageAttributesV1,
11 GenericDeviceMessageAttributesV1,
12 NullDeviceMessageAttributesV1,
13 },
14 v3::ClientDeviceMessageAttributesV3,
15};
16use buttplug_core::message::DeviceFeature;
17use getset::{CopyGetters, Getters, Setters};
18use serde::{Deserialize, Serialize};
19
20#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Getters, Setters)]
21pub struct ClientDeviceMessageAttributesV2 {
22 // Generic commands
23 #[getset(get = "pub")]
24 #[serde(rename = "VibrateCmd")]
25 #[serde(skip_serializing_if = "Option::is_none")]
26 pub(in crate::message) vibrate_cmd: Option<GenericDeviceMessageAttributesV2>,
27 #[getset(get = "pub")]
28 #[serde(rename = "RotateCmd")]
29 #[serde(skip_serializing_if = "Option::is_none")]
30 pub(in crate::message) rotate_cmd: Option<GenericDeviceMessageAttributesV2>,
31 #[getset(get = "pub")]
32 #[serde(rename = "LinearCmd")]
33 #[serde(skip_serializing_if = "Option::is_none")]
34 pub(in crate::message) linear_cmd: Option<GenericDeviceMessageAttributesV2>,
35 #[getset(get = "pub")]
36 #[serde(rename = "BatteryLevelCmd")]
37 #[serde(skip_serializing_if = "Option::is_none")]
38 pub(in crate::message) battery_level_cmd: Option<NullDeviceMessageAttributesV1>,
39
40 // RSSILevel is added post-serialization (only for bluetooth devices)
41 #[getset(get = "pub")]
42 #[serde(rename = "RSSILevelCmd")]
43 #[serde(skip_serializing_if = "Option::is_none")]
44 pub(in crate::message) rssi_level_cmd: Option<NullDeviceMessageAttributesV1>,
45
46 // StopDeviceCmd always exists
47 #[getset(get = "pub")]
48 #[serde(rename = "StopDeviceCmd")]
49 pub(in crate::message) stop_device_cmd: NullDeviceMessageAttributesV1,
50
51 // Needed to load from config for fallback, but unused here.
52 #[getset(get = "pub")]
53 #[serde(rename = "FleshlightLaunchFW12Cmd")]
54 #[serde(skip)]
55 pub(in crate::message) fleshlight_launch_fw12_cmd: Option<NullDeviceMessageAttributesV1>,
56 #[getset(get = "pub")]
57 #[serde(rename = "VorzeA10CycloneCmd")]
58 #[serde(skip)]
59 pub(in crate::message) vorze_a10_cyclone_cmd: Option<NullDeviceMessageAttributesV1>,
60}
61
62impl From<ClientDeviceMessageAttributesV2> for ClientDeviceMessageAttributesV1 {
63 fn from(other: ClientDeviceMessageAttributesV2) -> Self {
64 Self {
65 vibrate_cmd: other
66 .vibrate_cmd()
67 .as_ref()
68 .map(|x| GenericDeviceMessageAttributesV1::from(x.clone())),
69 rotate_cmd: other
70 .rotate_cmd()
71 .as_ref()
72 .map(|x| GenericDeviceMessageAttributesV1::from(x.clone())),
73 linear_cmd: other
74 .linear_cmd()
75 .as_ref()
76 .map(|x| GenericDeviceMessageAttributesV1::from(x.clone())),
77 stop_device_cmd: other.stop_device_cmd().clone(),
78 fleshlight_launch_fw12_cmd: other.fleshlight_launch_fw12_cmd().clone(),
79 vorze_a10_cyclone_cmd: other.vorze_a10_cyclone_cmd().clone(),
80 single_motor_vibrate_cmd: if other.vibrate_cmd().is_some() {
81 Some(NullDeviceMessageAttributesV1::default())
82 } else {
83 None
84 },
85 }
86 }
87}
88
89#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Getters, CopyGetters, Setters)]
90pub struct GenericDeviceMessageAttributesV2 {
91 #[getset(get_copy = "pub")]
92 #[serde(rename = "FeatureCount")]
93 pub(in crate::message) feature_count: u32,
94 #[getset(get = "pub")]
95 #[serde(rename = "StepCount")]
96 pub(in crate::message) step_count: Vec<u32>,
97}
98
99impl From<GenericDeviceMessageAttributesV2> for GenericDeviceMessageAttributesV1 {
100 fn from(attributes: GenericDeviceMessageAttributesV2) -> Self {
101 Self::new(attributes.feature_count())
102 }
103}
104
105impl From<Vec<DeviceFeature>> for ClientDeviceMessageAttributesV2 {
106 fn from(value: Vec<DeviceFeature>) -> Self {
107 ClientDeviceMessageAttributesV3::from(value).into()
108 }
109}