Buttplug sex toy control library
1use getset::{CopyGetters, Getters, MutGetters};
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5use crate::{ButtplugDeviceConfigError, ServerDeviceDefinition, ServerDeviceDefinitionBuilder};
6
7use super::feature::{ConfigBaseDeviceFeature, ConfigUserDeviceFeature};
8
9#[derive(Debug, Clone, Getters, CopyGetters, Serialize, Deserialize)]
10pub struct ConfigBaseDeviceDefinition {
11 #[getset(get = "pub")]
12 identifier: Option<Vec<String>>,
13 #[getset(get = "pub")]
14 /// Given name of the device this instance represents.
15 name: String,
16 #[getset(get_copy = "pub")]
17 id: Uuid,
18 #[getset(get = "pub")]
19 protocol_variant: Option<String>,
20 #[getset(get_copy = "pub")]
21 message_gap_ms: Option<u32>,
22 #[getset(get = "pub")]
23 features: Option<Vec<ConfigBaseDeviceFeature>>,
24}
25
26impl ConfigBaseDeviceDefinition {
27 pub fn update_with_configuration(&self, config: ConfigBaseDeviceDefinition) -> Self {
28 Self {
29 identifier: config.identifier().clone(),
30 name: config.name().clone(),
31 id: config.id(),
32 protocol_variant: config.protocol_variant.or(self.protocol_variant.clone()),
33 message_gap_ms: config.message_gap_ms.or(self.message_gap_ms),
34 features: config.features.or(self.features.clone()),
35 }
36 }
37}
38
39impl From<ConfigBaseDeviceDefinition> for ServerDeviceDefinition {
40 fn from(val: ConfigBaseDeviceDefinition) -> Self {
41 let mut builder = ServerDeviceDefinitionBuilder::new(&val.name, &val.id);
42 if let Some(variant) = val.protocol_variant {
43 builder.protocol_variant(&variant);
44 }
45 if let Some(gap) = val.message_gap_ms {
46 builder.message_gap_ms(gap);
47 }
48 if let Some(features) = val.features {
49 for feature in features {
50 builder.add_feature(&feature.into());
51 }
52 }
53 builder.finish()
54 }
55}
56
57#[derive(Serialize, Deserialize, Debug, Getters, CopyGetters, Default, Clone, MutGetters)]
58pub struct ConfigUserDeviceCustomization {
59 #[serde(default, skip_serializing_if = "Option::is_none")]
60 #[getset(get = "pub")]
61 display_name: Option<String>,
62 #[serde(default)]
63 #[getset(get_copy = "pub")]
64 allow: bool,
65 #[serde(default)]
66 #[getset(get_copy = "pub")]
67 deny: bool,
68 #[getset(get_copy = "pub", get_mut = "pub")]
69 index: u32,
70 #[getset(get_copy = "pub")]
71 #[serde(default, skip_serializing_if = "Option::is_none")]
72 message_gap_ms: Option<u32>,
73}
74
75impl From<&ServerDeviceDefinition> for ConfigUserDeviceCustomization {
76 fn from(value: &ServerDeviceDefinition) -> Self {
77 Self {
78 display_name: value.display_name().clone(),
79 allow: value.allow(),
80 deny: value.deny(),
81 index: value.index(),
82 message_gap_ms: value.message_gap_ms(),
83 }
84 }
85}
86
87#[derive(Debug, Clone, Getters, MutGetters, Serialize, Deserialize, CopyGetters)]
88pub struct ConfigUserDeviceDefinition {
89 #[getset(get_copy = "pub")]
90 id: Uuid,
91 #[getset(get_copy = "pub")]
92 base_id: Uuid,
93 #[getset(get = "pub")]
94 /// Message attributes for this device instance.
95 #[getset(get = "pub", get_mut = "pub")]
96 features: Vec<ConfigUserDeviceFeature>,
97 #[getset(get = "pub", get_mut = "pub")]
98 /// Per-user configurations specific to this device instance.
99 user_config: ConfigUserDeviceCustomization,
100}
101
102impl ConfigUserDeviceDefinition {
103 pub fn build_from_base_definition(
104 &self,
105 base: &ServerDeviceDefinition,
106 ) -> Result<ServerDeviceDefinition, ButtplugDeviceConfigError> {
107 let mut builder = ServerDeviceDefinitionBuilder::from_base(base, self.id, false);
108 builder.display_name(&self.user_config.display_name);
109 if let Some(message_gap_ms) = self.user_config.message_gap_ms {
110 builder.message_gap_ms(message_gap_ms);
111 }
112 self.user_config.allow.then(|| builder.allow(true));
113 self.user_config.deny.then(|| builder.deny(true));
114 builder.index(self.user_config.index);
115 if self.features().len() != base.features().len() {
116 return Err(ButtplugDeviceConfigError::UserFeatureMismatch);
117 }
118 for feature in self.features() {
119 if let Some(base_feature) = base.features().iter().find(|x| x.id() == feature.base_id()) {
120 builder.add_feature(&feature.with_base_feature(base_feature)?);
121 } else {
122 return Err(ButtplugDeviceConfigError::UserFeatureMismatch);
123 }
124 }
125 Ok(builder.finish())
126 }
127}
128
129impl From<&ServerDeviceDefinition> for ConfigUserDeviceDefinition {
130 fn from(value: &ServerDeviceDefinition) -> Self {
131 Self {
132 id: value.id(),
133 base_id: value.base_id().expect("Should always have a base id"),
134 features: value.features().iter().map(|x| x.into()).collect(),
135 user_config: value.into(),
136 }
137 }
138}