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

303 lines
9.1 KiB
Rust
Raw Normal View History

2025-09-16 21:07:44 +02:00
use crate::{
state_variables::StateVariable,
variable_types::{StateValue, UpnpVarType},
};
2025-10-02 18:39:32 +02:00
/// 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<V: UpnpVariable>(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");
/// }
/// }
/// ```
2025-09-16 21:07:44 +02:00
pub trait UpnpVariable {
2025-10-02 18:39:32 +02:00
/// 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`
2025-09-16 21:07:44 +02:00
fn get_definition(&self) -> &StateVariable;
2025-10-02 18:39:32 +02:00
/// 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());
/// }
/// ```
2025-09-16 21:07:44 +02:00
fn has_step(&self) -> bool {
2025-10-02 18:39:32 +02:00
self.get_definition().step.is_some()
2025-09-16 21:07:44 +02:00
}
2025-10-02 18:39:32 +02:00
/// 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
2025-09-16 21:07:44 +02:00
fn get_step(&self) -> Option<StateValue> {
2025-10-02 18:39:32 +02:00
self.get_definition().step.clone()
2025-09-16 21:07:44 +02:00
}
2025-10-02 18:39:32 +02:00
/// 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.
2025-09-16 21:07:44 +02:00
fn has_range(&self) -> bool {
2025-10-02 18:39:32 +02:00
self.get_definition().value_range.is_some()
2025-09-16 21:07:44 +02:00
}
2025-10-02 18:39:32 +02:00
/// 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.
2025-09-16 21:07:44 +02:00
fn is_modifiable(&self) -> bool {
2025-10-02 18:39:32 +02:00
self.get_definition().modifiable
2025-09-16 21:07:44 +02:00
}
2025-10-02 18:39:32 +02:00
/// 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).
2025-09-16 21:07:44 +02:00
fn has_event_conditions(&self) -> bool {
2025-10-02 18:39:32 +02:00
let guard = self.get_definition().event_conditions.blocking_read();
!guard.is_empty()
2025-09-16 21:07:44 +02:00
}
2025-10-02 18:39:32 +02:00
/// 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).
2025-09-16 21:07:44 +02:00
fn has_event_condition(&self, name: &String) -> bool {
2025-10-02 18:39:32 +02:00
let guard = self.get_definition().event_conditions.blocking_read();
guard.contains_key(name)
2025-09-16 21:07:44 +02:00
}
2025-10-02 18:39:32 +02:00
/// Indique si la variable a une description non vide.
///
/// # Returns
///
/// `true` si une description existe et n'est pas vide, `false` sinon.
2025-09-16 21:07:44 +02:00
fn has_description(&self) -> bool {
2025-10-02 18:39:32 +02:00
!self.get_definition().description.is_empty()
2025-09-16 21:07:44 +02:00
}
2025-10-02 18:39:32 +02:00
/// 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
2025-09-16 21:07:44 +02:00
fn get_description(&self) -> String {
2025-10-02 18:39:32 +02:00
self.get_definition().description.clone()
2025-09-16 21:07:44 +02:00
}
2025-10-02 18:39:32 +02:00
/// 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).
2025-09-16 21:07:44 +02:00
fn has_default(&self) -> bool {
2025-10-02 18:39:32 +02:00
self.get_definition().default_value.is_some()
2025-09-16 21:07:44 +02:00
}
2025-10-02 18:39:32 +02:00
/// 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);
/// ```
2025-09-16 21:07:44 +02:00
fn get_default(&self) -> StateValue {
self.get_definition()
.default_value
.clone()
.unwrap_or_else(|| self.get_definition().as_state_var_type().default_value())
}
2025-10-01 07:42:16 +02:00
2025-10-02 18:39:32 +02:00
/// 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).
2025-09-16 21:07:44 +02:00
fn has_allowed_values(&self) -> bool {
2025-10-02 18:39:32 +02:00
let guard = self.get_definition()
.allowed_values
.blocking_read();
!guard.is_empty()
2025-09-16 21:07:44 +02:00
}
2025-10-02 18:39:32 +02:00
/// 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
.blocking_read();
guard.contains(value)
2025-09-16 21:07:44 +02:00
}
2025-10-02 18:39:32 +02:00
/// 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
2025-09-16 21:07:44 +02:00
fn is_sending_notification(&self) -> bool {
self.get_definition().send_events
}
2025-10-02 18:39:32 +02:00
/// 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.
2025-09-16 21:07:44 +02:00
fn has_value_parser(&self) -> bool {
self.get_definition().parse.is_some()
}
2025-10-02 18:39:32 +02:00
/// 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.
2025-09-16 21:07:44 +02:00
fn has_value_marshaler(&self) -> bool {
self.get_definition().marshal.is_some()
}
}