Files
pmomusic/pmoupnp/src/state_variables/variable_methods.rs

432 lines
13 KiB
Rust

use std::{
collections::HashMap,
fmt,
sync::Arc,
};
use std::sync::RwLock;
use xmltree::{Element, XMLNode};
use crate::{
UpnpObjectType, UpnpTyped,
object_trait::{UpnpModel, UpnpObject},
state_variables::{
StateConditionFunc, StateVarInstance, StateVariable, StringValueParser, ValueSerializer,
variable_trait::UpnpVariable,
},
value_ranges::ValueRange,
variable_types::{StateValue, StateValueError, StateVarType, UpnpVarType},
};
impl UpnpTyped for StateVariable {
fn as_upnp_object_type(&self) -> &UpnpObjectType {
&self.object
}
}
impl UpnpVarType for StateVariable {
fn as_state_var_type(&self) -> StateVarType {
self.value_type.as_state_var_type() // utilise ton From<&StateValue> existant
}
}
impl UpnpObject for StateVariable {
fn to_xml_element(&self) -> Element {
// Création de l'élément racine <stateVariable>
let mut root = Element::new("stateVariable");
root.attributes.insert(
"sendEvents".to_string(),
if self.send_events { "yes" } else { "no" }.to_string(),
);
// <name>
let mut name_elem = Element::new("name");
name_elem
.children
.push(XMLNode::Text(self.get_name().clone()));
// <dataType>
let mut datatype_elem = Element::new("dataType");
datatype_elem
.children
.push(XMLNode::Text(self.value_type.to_string())); // StateVarType doit impl Display
// <defaultValue> si défini
if let Some(default) = &self.default_value {
let mut def_elem = Element::new("defaultValue");
def_elem.children.push(XMLNode::Text(default.to_string()));
root.children.push(XMLNode::Element(def_elem));
}
// <allowedValueList> si défini
let av = self.allowed_values.read().unwrap();
if !av.is_empty() {
let mut list_elem = Element::new("allowedValueList");
for val in av.iter() {
let mut val_elem = Element::new("allowedValue");
val_elem.children.push(XMLNode::Text(val.to_string()));
list_elem.children.push(XMLNode::Element(val_elem));
}
root.children.push(XMLNode::Element(list_elem));
}
// <allowedValueRange> si défini
if let Some(range) = &self.value_range {
let mut range_elem = Element::new("allowedValueRange");
let mut min_elem = Element::new("minimum");
min_elem
.children
.push(XMLNode::Text(range.get_minimum().to_string()));
range_elem.children.push(XMLNode::Element(min_elem));
let mut max_elem = Element::new("maximum");
max_elem
.children
.push(XMLNode::Text(range.get_maximum().to_string()));
range_elem.children.push(XMLNode::Element(max_elem));
if let Some(step) = &self.step {
let mut step_elem = Element::new("step");
step_elem.children.push(XMLNode::Text(step.to_string()));
range_elem.children.push(XMLNode::Element(step_elem));
}
root.children.push(XMLNode::Element(range_elem));
}
// Ajouter les enfants communs
root.children.push(XMLNode::Element(name_elem));
root.children.push(XMLNode::Element(datatype_elem));
root
}
}
impl UpnpModel for StateVariable {
type Instance = StateVarInstance;
}
impl Clone for StateVariable {
fn clone(&self) -> Self {
// clone safe des structures protégées par RwLock en prenant un read lock
let event_conditions_clone = {
// si le lock est "poisoned" on panic - tu peux adapter la gestion si tu veux
let guard = self
.event_conditions
.read().unwrap();
// nécessite que Key: Clone, Value: Clone
Arc::new(RwLock::new(guard.clone()))
};
let allowed_values_clone = {
let guard = self
.allowed_values
.read().unwrap();
Arc::new(RwLock::new(guard.clone()))
};
Self {
object: self.object.clone(),
value_type: self.value_type.clone(),
step: self.step.clone(),
modifiable: self.modifiable,
event_conditions: event_conditions_clone,
description: self.description.clone(),
default_value: self.default_value.clone(),
value_range: self.value_range.clone(),
allowed_values: allowed_values_clone,
send_events: self.send_events,
// parse et marshal sont typiquement des Arc<dyn ...> — on clone l'Arc (shallow).
// Deep-cloner une closure ou un trait-objet n'est pas possible en général.
parse: self.parse.clone(),
marshal: self.marshal.clone(),
}
}
}
impl fmt::Debug for StateVariable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("StateVariable")
.field("object", &self.object)
.field("value_type", &self.value_type)
.field("step", &self.step)
.field("modifiable", &self.modifiable)
.field(
"event_conditions",
&format_args!(
"len={}",
self.event_conditions.read().unwrap().len()
),
)
.field("description", &self.description)
.field("default_value", &self.default_value)
.field("value_range", &self.value_range)
.field(
"allowed_values",
&format_args!(
"len={}",
self.allowed_values.read().unwrap().len()
),
)
.field("send_events", &self.send_events)
.field(
"parse",
&self
.parse
.as_ref()
.map(|_| "Some(StringValueParser)")
.unwrap_or("None"),
)
.field(
"marshal",
&self
.marshal
.as_ref()
.map(|_| "Some(ValueSerializer)")
.unwrap_or("None"),
)
.finish()
}
}
impl UpnpVariable for StateVariable {
fn get_definition(&self) -> &StateVariable {
return self;
}
}
impl StateVariable {
pub fn new(vartype: StateVarType, name: String) -> StateVariable {
Self {
object: UpnpObjectType {
name,
object_type: "StateVariable".to_string(),
},
value_type: vartype.clone(),
step: None,
modifiable: true,
event_conditions: Arc::new(RwLock::new(HashMap::new())),
description: "".to_string(),
default_value: None,
value_range: None,
allowed_values: Arc::new(RwLock::new(Vec::new())),
send_events: false,
parse: None,
marshal: None,
}
}
pub fn set_step(&mut self, step: StateValue) -> Result<(), StateValueError> {
if self.as_state_var_type() != step.as_state_var_type() {
return Err(StateValueError::TypeError("Bad step type".to_string()));
}
self.step = Some(step);
Ok(())
}
pub fn set_range(&mut self, min: &StateValue, max: &StateValue) -> Result<(), StateValueError> {
if self.as_state_var_type() != min.as_state_var_type() {
return Err(StateValueError::TypeError("Bad range type".to_string()));
}
let range = ValueRange::new(min, max)?; // ? propage l'erreur si elle existe
self.value_range = Some(range);
Ok(())
}
pub fn update_minimum(&mut self, min: &StateValue) -> Result<(), StateValueError> {
if !self.has_range() {
return Err(StateValueError::RangeError(
"No range specified for this variable".to_string(),
));
}
if self
.value_range
.as_ref()
.expect("Range is not defined")
.as_state_var_type()
!= min.as_state_var_type()
{
return Err(StateValueError::TypeError(
"new minimum is not the same than state variable".to_string(),
));
}
self.value_range
.as_mut()
.expect("Range is not defined")
.set_minimum(min);
return Ok(());
}
pub fn update_maximum(&mut self, min: &StateValue) -> Result<(), StateValueError> {
if !self.has_range() {
return Err(StateValueError::RangeError(
"No range specified for this variable".to_string(),
));
}
if self
.value_range
.as_ref()
.expect("Range is not defined")
.as_state_var_type()
!= min.as_state_var_type()
{
return Err(StateValueError::TypeError(
"new minimum is not the same than state variable".to_string(),
));
}
self.value_range
.as_mut()
.expect("Range is not defined")
.set_maximum(min);
return Ok(());
}
pub fn get_range(&self) -> Option<&ValueRange> {
return self.value_range.as_ref();
}
pub fn set_modifiable(&mut self) {
self.modifiable = true;
}
pub fn set_not_modifiable(&mut self) {
self.modifiable = false;
}
pub fn add_event_condition(&self, name: String, func: StateConditionFunc) {
// on lock en écriture
let mut guard = self.event_conditions.write().unwrap();
guard.insert(name, func);
// le lock est automatiquement relâché ici (RAII)
}
pub fn remove_event_condition(&self, name: &str) {
let mut guard = self.event_conditions.write().unwrap();
guard.remove(name);
}
pub fn clear_event_conditions(&mut self) {
let mut guard = self.event_conditions.write().unwrap();
guard.clear()
}
pub fn set_description(&mut self, description: String) {
self.description = description;
}
pub fn set_default(&mut self, value: &StateValue) -> Result<(), StateValueError> {
if self.as_state_var_type() != value.as_state_var_type() {
return Err(StateValueError::TypeError(
"value does not have the right type".to_string(),
));
}
self.default_value = Some(value.clone());
return Ok(());
}
pub fn unset_default(&mut self) {
self.default_value = None;
}
pub fn extend_allowed_values(&mut self, values: &[StateValue]) -> Result<(), StateValueError> {
let mut av = self
.allowed_values
.write().unwrap();
for v in values {
if self.as_state_var_type() == v.as_state_var_type() {
av.push(v.clone());
} else {
return Err(StateValueError::TypeError(
"new allowed value does not have the right type".to_string(),
));
}
}
Ok(())
}
pub fn push_allowed_value(&mut self, value: &StateValue) -> Result<(), StateValueError> {
let mut av = self
.allowed_values
.write().unwrap();
if self.as_state_var_type() == value.as_state_var_type() {
av.push(value.clone());
} else {
return Err(StateValueError::TypeError(
"new allowed value does not have the right type".to_string(),
));
}
return Ok(());
}
pub fn set_send_notification(&mut self) {
self.send_events = true;
}
pub fn unset_send_notification(&mut self) {
self.send_events = false;
}
pub fn set_value_parser(&mut self, parser: StringValueParser) -> Result<(), StateValueError> {
if self.as_state_var_type() == StateVarType::String {
self.parse = Some(parser);
return Ok(());
}
return Err(StateValueError::TypeError(
"Only String variables can have a parser".to_string(),
));
}
pub fn unset_value_parser(&mut self) {
self.parse = None;
}
pub fn set_value_marshaler(
&mut self,
marshaler: ValueSerializer,
) -> Result<(), StateValueError> {
if self.as_state_var_type() == StateVarType::String {
self.marshal = Some(marshaler);
return Ok(());
}
return Err(StateValueError::TypeError(
"Only String variables can have a marshaler".to_string(),
));
}
pub fn unset_value_marshaler(&mut self) {
self.marshal = None;
}
/// Retourne le type de données de cette variable.
pub fn get_data_type(&self) -> &StateVarType {
&self.value_type
}
/// Retourne la valeur par défaut si définie.
pub fn get_default_value(&self) -> Option<&StateValue> {
self.default_value.as_ref()
}
/// Retourne le step si défini.
pub fn get_step(&self) -> Option<&StateValue> {
self.step.as_ref()
}
/// Retourne les valeurs autorisées.
pub fn get_allowed_values(&self) -> Vec<StateValue> {
self.allowed_values.read().unwrap().clone()
}
/// Indique si cette variable envoie des notifications d'événements.
pub fn sends_events(&self) -> bool {
self.send_events
}
}