use crate::{ state_variables::StateVariable, variable_types::{StateValue, UpnpVarType}, }; /// Trait pour accéder aux propriétés et contraintes d'une variable UPnP. /// /// Ce trait fournit une interface uniforme pour interroger les métadonnées, /// contraintes et comportements d'une variable UPnP, qu'il s'agisse d'une /// définition ([`StateVariable`]) ou d'une instance ([`StateVarInstance`]). /// /// # Architecture /// /// Le trait utilise le pattern "trait avec implémentation par défaut" : /// - Une seule méthode requise : [`get_definition`](Self::get_definition) /// - Toutes les autres méthodes sont implémentées par défaut en déléguant à la définition /// /// Cela permet une interface cohérente entre modèles et instances sans duplication de code. /// /// # Hiérarchie /// /// ```text /// UpnpVariable /// ├─> StateVariable (get_definition() retourne self) /// └─> StateVarInstance (get_definition() retourne self.definition) /// ``` /// /// # Examples /// /// ```ignore /// fn display_variable_info(var: &V) { /// println!("Variable: {}", var.get_definition().get_name()); /// /// if var.has_default() { /// println!("Default: {:?}", var.get_default()); /// } /// /// if var.has_range() { /// println!("Has range constraints"); /// } /// /// if var.has_allowed_values() { /// println!("Has allowed values list"); /// } /// } /// ``` pub trait UpnpVariable { /// Retourne une référence vers la définition de la variable. /// /// Cette méthode est la base de toutes les autres méthodes du trait. /// /// # Implementation /// /// - Pour [`StateVariable`] : retourne `self` /// - Pour [`StateVarInstance`] : retourne `self.definition` fn get_definition(&self) -> &StateVariable; /// Indique si la variable a un pas (step) défini. /// /// Le pas définit l'incrément minimal entre deux valeurs valides pour /// les types numériques. /// /// # Returns /// /// `true` si un pas est défini, `false` sinon. /// /// # Examples /// /// ```ignore /// if var.has_step() { /// println!("Step: {:?}", var.get_step()); /// } /// ``` fn has_step(&self) -> bool { self.get_definition().step.is_some() } /// Retourne le pas (step) de la variable s'il est défini. /// /// # Returns /// /// - `Some(StateValue)` si un pas est défini /// - `None` sinon /// /// # See also /// /// - [`has_step`](Self::has_step) pour tester l'existence fn get_step(&self) -> Option { self.get_definition().step.clone() } /// Indique si la variable a une plage de valeurs (range) définie. /// /// La plage définit les valeurs minimale et maximale acceptables. /// /// # Returns /// /// `true` si une plage est définie, `false` sinon. fn has_range(&self) -> bool { self.get_definition().value_range.is_some() } /// Indique si la variable est modifiable. /// /// Une variable non modifiable est en lecture seule. /// /// # Returns /// /// `true` si la variable peut être modifiée, `false` sinon. fn is_modifiable(&self) -> bool { self.get_definition().modifiable } /// Indique si la variable a des conditions d'événement définies. /// /// Les conditions d'événement déterminent quand des notifications /// doivent être envoyées lors de changements de valeur. /// /// # Returns /// /// `true` si au moins une condition d'événement existe, `false` sinon. /// /// # Note /// /// Retourne `false` si le lock est empoisonné (poisoned). fn has_event_conditions(&self) -> bool { let guard = self.get_definition().event_conditions.read().unwrap(); !guard.is_empty() } /// Vérifie si une condition d'événement spécifique existe. /// /// # Arguments /// /// * `name` - Le nom de la condition à rechercher /// /// # Returns /// /// `true` si la condition existe, `false` sinon. /// /// # Note /// /// Retourne `false` si le lock est empoisonné (poisoned). fn has_event_condition(&self, name: &String) -> bool { let guard = self.get_definition().event_conditions.read().unwrap(); guard.contains_key(name) } /// Indique si la variable a une description non vide. /// /// # Returns /// /// `true` si une description existe et n'est pas vide, `false` sinon. fn has_description(&self) -> bool { !self.get_definition().description.is_empty() } /// Retourne la description de la variable. /// /// # Returns /// /// La description sous forme de `String`. Peut être vide. /// /// # See also /// /// - [`has_description`](Self::has_description) pour tester si non vide fn get_description(&self) -> String { self.get_definition().description.clone() } /// Indique si la variable a une valeur par défaut définie explicitement. /// /// # Returns /// /// `true` si une valeur par défaut est explicitement définie, `false` sinon. /// /// # Note /// /// Même si cette méthode retourne `false`, [`get_default`](Self::get_default) /// retournera toujours une valeur (la valeur par défaut du type). fn has_default(&self) -> bool { self.get_definition().default_value.is_some() } /// Retourne la valeur par défaut de la variable. /// /// # Returns /// /// La valeur par défaut. Si aucune valeur par défaut n'est explicitement /// définie, retourne la valeur par défaut du type de la variable /// (ex: 0 pour les entiers, chaîne vide pour String, etc.). /// /// # Examples /// /// ```ignore /// let default = var.get_default(); /// println!("Default value: {:?}", default); /// ``` fn get_default(&self) -> StateValue { self.get_definition() .default_value .clone() .unwrap_or_else(|| self.get_definition().as_state_var_type().default_value()) } /// Indique si la variable a une liste de valeurs autorisées. /// /// Lorsqu'une liste de valeurs autorisées est définie, seules ces valeurs /// sont acceptables pour la variable. /// /// # Returns /// /// `true` si une liste non vide de valeurs autorisées existe, `false` sinon. /// /// # Note /// /// Retourne `false` si le lock est empoisonné (poisoned). fn has_allowed_values(&self) -> bool { let guard = self.get_definition().allowed_values.read().unwrap(); !guard.is_empty() } /// Vérifie si une valeur fait partie des valeurs autorisées. /// /// # Arguments /// /// * `value` - La valeur à vérifier /// /// # Returns /// /// `true` si la valeur est dans la liste des valeurs autorisées, `false` sinon. /// Retourne également `false` si aucune liste de valeurs autorisées n'est définie /// ou si le lock est empoisonné. /// /// # Examples /// /// ```ignore /// let value = StateValue::String("ON".to_string()); /// if var.is_an_allowed_value(&value) { /// println!("Value is allowed"); /// } /// ``` /// /// # Note /// /// Si aucune liste de valeurs autorisées n'est définie, cette méthode /// retourne `false`. Utilisez [`has_allowed_values`](Self::has_allowed_values) /// pour distinguer "pas de liste" de "valeur non autorisée". fn is_an_allowed_value(&self, value: &StateValue) -> bool { let guard = self.get_definition().allowed_values.read().unwrap(); guard.contains(value) } /// Indique si la variable envoie des notifications d'événement. /// /// Les notifications d'événement sont envoyées aux abonnés lorsque /// la valeur de la variable change. /// /// # Returns /// /// `true` si les notifications sont activées, `false` sinon. /// /// # See also /// /// - [`has_event_conditions`](Self::has_event_conditions) pour vérifier /// les conditions d'envoi d'événements fn is_sending_notification(&self) -> bool { self.get_definition().send_events } /// Indique si la variable a un parser de valeur personnalisé. /// /// Un parser personnalisé est utilisé pour convertir des chaînes de /// caractères en valeurs typées. Disponible uniquement pour les variables /// de type String. /// /// # Returns /// /// `true` si un parser est défini, `false` sinon. fn has_value_parser(&self) -> bool { self.get_definition().parse.is_some() } /// Indique si la variable a un marshaler de valeur personnalisé. /// /// Un marshaler personnalisé est utilisé pour sérialiser des valeurs /// en chaînes de caractères. Disponible uniquement pour les variables /// de type String. /// /// # Returns /// /// `true` si un marshaler est défini, `false` sinon. fn has_value_marshaler(&self) -> bool { self.get_definition().marshal.is_some() } }