From a23d9bf845a0f4bca258d0b68ffd1c58494dd454 Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Wed, 1 Oct 2025 07:42:16 +0200 Subject: [PATCH] On reformate le code ;-) --- Cargo.lock | 245 ++++++++++++++++++ pmoconfig/src/lib.rs | 2 +- pmoupnp/Cargo.toml | 3 + pmoupnp/src/lib.rs | 7 +- pmoupnp/src/object_trait.rs | 6 +- pmoupnp/src/server/logs/mod.rs | 11 +- pmoupnp/src/server/logs/sselayer.rs | 7 +- pmoupnp/src/server/mod.rs | 119 ++++++--- pmoupnp/src/state_variables/errors.rs | 14 +- .../src/state_variables/instance_methods.rs | 10 +- pmoupnp/src/state_variables/mod.rs | 29 ++- .../src/state_variables/variable_methods.rs | 10 +- pmoupnp/src/state_variables/variable_trait.rs | 2 +- pmoupnp/src/value_ranges/mod.rs | 3 +- pmoupnp/src/variable_types/cast.rs | 25 +- pmoupnp/src/variable_types/default_value.rs | 26 +- pmoupnp/src/variable_types/display_type.rs | 1 - pmoupnp/src/variable_types/display_value.rs | 5 +- pmoupnp/src/variable_types/errors.rs | 14 +- pmoupnp/src/variable_types/fromstr.rs | 5 +- pmoupnp/src/variable_types/mod.rs | 30 +-- pmoupnp/src/variable_types/type_methods.rs | 20 +- pmoupnp/src/variable_types/value_methods.rs | 1 - pmoupnp/src/variable_types/value_trait.rs | 3 +- .../variable_types/values_from_datetime.rs | 18 +- pmoupnp/src/variable_types/values_from_f32.rs | 42 ++- pmoupnp/src/variable_types/values_from_f64.rs | 10 +- pmoupnp/src/variable_types/values_from_i16.rs | 13 +- pmoupnp/src/variable_types/values_from_i32.rs | 11 +- pmoupnp/src/variable_types/values_from_i64.rs | 8 +- pmoupnp/src/variable_types/values_from_i8.rs | 17 +- .../variable_types/values_from_naivedate.rs | 15 +- .../values_from_naivedatetime.rs | 16 +- .../variable_types/values_from_naivetime.rs | 14 +- pmoupnp/src/variable_types/values_from_u16.rs | 15 +- pmoupnp/src/variable_types/values_from_u32.rs | 13 +- pmoupnp/src/variable_types/values_from_u8.rs | 11 +- pmoupnp/src/variable_types/values_from_uri.rs | 4 +- .../src/variable_types/values_from_uuid.rs | 7 +- .../src/variable_types/values_from_vec_u8.rs | 13 +- pmoutils/src/ip_utils.rs | 15 +- pmoutils/src/lib.rs | 2 +- 42 files changed, 553 insertions(+), 289 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63ce9106..75ba6639 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,6 +54,15 @@ version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -300,6 +309,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -310,6 +328,52 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "digest" version = "0.10.7" @@ -364,6 +428,17 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "libz-rs-sys", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -770,6 +845,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "1.1.0" @@ -799,6 +880,8 @@ checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", "hashbrown", + "serde", + "serde_core", ] [[package]] @@ -850,6 +933,15 @@ dependencies = [ "libc", ] +[[package]] +name = "libz-rs-sys" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "840db8cf39d9ec4dd794376f38acc40d0fc65eec2a8f484f7fd375b84602becd" +dependencies = [ + "zlib-rs", +] + [[package]] name = "litemap" version = "0.8.0" @@ -1052,7 +1144,10 @@ dependencies = [ "tracing", "tracing-subscriber", "url", + "utoipa", + "utoipa-swagger-ui", "uuid", + "validator", "xmltree", ] @@ -1072,6 +1167,28 @@ dependencies = [ "zerovec", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.101" @@ -1116,6 +1233,18 @@ dependencies = [ "thiserror", ] +[[package]] +name = "regex" +version = "1.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + [[package]] name = "regex-automata" version = "0.4.11" @@ -1314,6 +1443,12 @@ dependencies = [ "libc", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "slab" version = "0.4.11" @@ -1342,6 +1477,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "2.0.106" @@ -1595,6 +1736,48 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utoipa" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fcc29c80c21c31608227e0912b2d7fddba57ad76b606890627ba8ee7964e993" +dependencies = [ + "indexmap", + "serde", + "serde_json", + "utoipa-gen", +] + +[[package]] +name = "utoipa-gen" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d79d08d92ab8af4c5e8a6da20c47ae3f61a0f1dabc1997cdf2d082b757ca08b" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn", +] + +[[package]] +name = "utoipa-swagger-ui" +version = "9.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d047458f1b5b65237c2f6dc6db136945667f40a7668627b3490b9513a3d43a55" +dependencies = [ + "axum", + "base64", + "mime_guess", + "regex", + "rust-embed", + "serde", + "serde_json", + "url", + "utoipa", + "zip", +] + [[package]] name = "uuid" version = "1.18.1" @@ -1606,6 +1789,36 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "validator" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43fb22e1a008ece370ce08a3e9e4447a910e92621bb49b85d6e48a45397e7cfa" +dependencies = [ + "idna", + "once_cell", + "regex", + "serde", + "serde_derive", + "serde_json", + "url", + "validator_derive", +] + +[[package]] +name = "validator_derive" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7df16e474ef958526d1205f6dda359fdfab79d9aa6d54bafcb92dcd07673dca" +dependencies = [ + "darling", + "once_cell", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "valuable" version = "0.1.1" @@ -1980,3 +2193,35 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zip" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12598812502ed0105f607f941c386f43d441e00148fce9dec3ca5ffb0bde9308" +dependencies = [ + "arbitrary", + "crc32fast", + "flate2", + "indexmap", + "memchr", + "zopfli", +] + +[[package]] +name = "zlib-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f06ae92f42f5e5c42443fd094f245eb656abf56dd7cce9b8b263236565e00f2" + +[[package]] +name = "zopfli" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] diff --git a/pmoconfig/src/lib.rs b/pmoconfig/src/lib.rs index 0c39ac7e..580ed071 100644 --- a/pmoconfig/src/lib.rs +++ b/pmoconfig/src/lib.rs @@ -16,7 +16,7 @@ const DEFAULT_CONFIG: &str = include_str!("pmomusic.yaml"); lazy_static! { static ref CONFIG: Arc = - Arc::new(Config::load_config("").expect("Failed to load PMOMusic configuration")) ; + Arc::new(Config::load_config("").expect("Failed to load PMOMusic configuration")); } const ENV_CONFIG_FILE: &str = "PMOMUSIC_CONFIG"; diff --git a/pmoupnp/Cargo.toml b/pmoupnp/Cargo.toml index 89ff943b..6f7e32b1 100644 --- a/pmoupnp/Cargo.toml +++ b/pmoupnp/Cargo.toml @@ -31,3 +31,6 @@ axum-server = "0.7.2" axum-embed = "0.1.0" rust-embed = "8.7.2" anyhow = "1.0" +utoipa = { version = "5.4.0", features = ["axum_extras"] } +utoipa-swagger-ui = { version = "9.0.2", features = ["axum"] } +validator = { version = "0.20.0", features = ["derive"] } diff --git a/pmoupnp/src/lib.rs b/pmoupnp/src/lib.rs index 114fc40e..63ce81fa 100644 --- a/pmoupnp/src/lib.rs +++ b/pmoupnp/src/lib.rs @@ -1,15 +1,14 @@ mod object_trait; -pub mod variable_types; +pub mod server; pub mod state_variables; pub mod value_ranges; -pub mod server; +pub mod variable_types; pub use crate::object_trait::UpnpObject; - #[derive(Clone)] pub struct UpnpObjectType { name: String, object_type: String, -} \ No newline at end of file +} diff --git a/pmoupnp/src/object_trait.rs b/pmoupnp/src/object_trait.rs index fbc373e1..1c59c3f7 100644 --- a/pmoupnp/src/object_trait.rs +++ b/pmoupnp/src/object_trait.rs @@ -2,12 +2,11 @@ use xmltree::{Element, EmitterConfig}; use crate::UpnpObjectType; - pub trait UpnpObject { fn as_upnp_object_type(&self) -> &UpnpObjectType; fn to_xml_element(&self) -> Element; - fn get_name(&self)-> &String { + fn get_name(&self) -> &String { return &self.as_upnp_object_type().name; } @@ -35,5 +34,4 @@ pub trait UpnpObject { xml_string } - -} \ No newline at end of file +} diff --git a/pmoupnp/src/server/logs/mod.rs b/pmoupnp/src/server/logs/mod.rs index 312bcd40..6ff83ece 100644 --- a/pmoupnp/src/server/logs/mod.rs +++ b/pmoupnp/src/server/logs/mod.rs @@ -10,9 +10,12 @@ use std::{ }; use axum::{ - extract::{Query, State}, - response::{sse::{Event, KeepAlive, Sse}, IntoResponse}, Json, + extract::{Query, State}, + response::{ + IntoResponse, + sse::{Event, KeepAlive, Sse}, + }, }; use serde::{Deserialize, Serialize}; use tokio::sync::broadcast; @@ -59,8 +62,6 @@ impl LogState { } } - - /// Query params pour /log-sse #[derive(Debug, Deserialize)] pub struct LogQuery { @@ -85,7 +86,7 @@ pub async fn log_sse( Query(params): Query, ) -> impl IntoResponse { let mut rx = state.subscribe(); - + // Récupérer l'historique du buffer let history = state.dump(); diff --git a/pmoupnp/src/server/logs/sselayer.rs b/pmoupnp/src/server/logs/sselayer.rs index 017523f6..4d2ec3fa 100644 --- a/pmoupnp/src/server/logs/sselayer.rs +++ b/pmoupnp/src/server/logs/sselayer.rs @@ -1,6 +1,6 @@ +use tracing::field::{Field, Visit}; use tracing::{Event, Subscriber}; -use tracing_subscriber::{layer::Context, Layer}; -use tracing::field::{Visit, Field}; +use tracing_subscriber::{Layer, layer::Context}; use super::{LogEntry, LogState}; use std::time::SystemTime; @@ -26,7 +26,8 @@ impl Visit for LogVisitor { if !self.message.is_empty() { self.message.push(' '); } - self.message.push_str(&format!("{}={:?}", field.name(), value)); + self.message + .push_str(&format!("{}={:?}", field.name(), value)); } } } diff --git a/pmoupnp/src/server/mod.rs b/pmoupnp/src/server/mod.rs index 503661c4..1ed5e125 100644 --- a/pmoupnp/src/server/mod.rs +++ b/pmoupnp/src/server/mod.rs @@ -10,38 +10,8 @@ //! - ⚛️ **Applications SPA** : Support pour Vue.js/React avec `add_spa()` //! - 🔀 **Redirections** : Redirigez des routes avec `add_redirect()` //! - 🎯 **Handlers personnalisés** : Support SSE, WebSocket, etc. avec `add_handler_with_state()` +//! - 📚 **Documentation API** : OpenAPI/Swagger automatique avec `add_openapi()` //! - ⚡ **Gestion gracieuse** : Arrêt propre sur Ctrl+C -//! -//! ## Exemple d'utilisation -//! -//! ```rust,no_run -//! use pmoupnp::server::{ServerBuilder, Server}; -//! use rust_embed::RustEmbed; -//! -//! #[derive(RustEmbed, Clone)] -//! #[folder = "static/"] -//! struct Assets; -//! -//! #[tokio::main] -//! async fn main() { -//! let mut server = ServerBuilder::new("MyAPI", "http://localhost:3000", 3000) -//! .build(); -//! -//! // Route JSON simple -//! server.add_route("/api/hello", || async { -//! serde_json::json!({"message": "Hello World"}) -//! }).await; -//! -//! // Redirection -//! server.add_redirect("/", "/app").await; -//! -//! // Application Vue.js -//! server.add_spa::("/app").await; -//! -//! server.start().await; -//! server.wait().await; -//! } -//! ``` pub mod logs; @@ -55,13 +25,18 @@ use rust_embed::RustEmbed; use serde::Serialize; use std::{net::SocketAddr, sync::Arc}; use tokio::{signal, sync::RwLock, task::JoinHandle}; -use tracing::{info,warn,debug,error}; +use tracing::{debug, error, info, warn}; +use utoipa::OpenApi; +use utoipa_swagger_ui::SwaggerUi; /// Info serveur sérialisable -#[derive(Clone, Serialize)] +#[derive(Clone, Serialize, utoipa::ToSchema)] pub struct ServerInfo { + /// Nom du serveur pub name: String, + /// URL de base pub base_url: String, + /// Port HTTP pub http_port: u16, } @@ -71,6 +46,7 @@ pub struct Server { base_url: String, http_port: u16, router: Arc>, + api_router: Arc>>, join_handle: Option>, } @@ -99,6 +75,7 @@ impl Server { base_url: base_url.into(), http_port, router: Arc::new(RwLock::new(Router::new())), + api_router: Arc::new(RwLock::new(None)), join_handle: None, } } @@ -111,7 +88,6 @@ impl Server { return Self::new("PMO-Music-Server", url, port); } - /// Ajoute une route dynamique /// Ajoute une route JSON dynamique /// /// Crée un endpoint qui retourne du JSON. La closure fournie sera appelée @@ -193,9 +169,9 @@ impl Server { E: RustEmbed + Clone + Send + Sync + 'static, { let serve = ServeEmbed::::new(); - + let mut r = self.router.write().await; - + if path == "/" { *r = std::mem::take(&mut *r).fallback_service(serve); } else { @@ -253,9 +229,9 @@ impl Server { axum_embed::FallbackBehavior::Ok, Some("index.html".to_string()), ); - + let mut r = self.router.write().await; - + if path == "/" { *r = std::mem::take(&mut *r).fallback_service(serve); } else { @@ -343,9 +319,7 @@ impl Server { T: 'static, S: Clone + Send + Sync + 'static, { - let route = Router::new() - .route("/", get(handler)) - .with_state(state); + let route = Router::new().route("/", get(handler)).with_state(state); let mut r = self.router.write().await; *r = std::mem::take(&mut *r).nest(path, route); @@ -413,6 +387,54 @@ impl Server { } } + /// Ajoute une API documentée avec OpenAPI + /// + /// Monte un routeur d'API sous `/api` et active Swagger UI sur `/swagger-ui` + /// + /// # Arguments + /// + /// * `api_router` - Router Axum contenant les routes API + /// * `openapi` - Spécification OpenAPI générée par utoipa + /// + /// # Exemple + /// + /// ```rust,no_run + /// use utoipa::OpenApi; + /// use axum::{Router, Json, routing::get}; + /// + /// #[derive(utoipa::OpenApi)] + /// #[openapi( + /// paths(get_users), + /// components(schemas(User)) + /// )] + /// struct ApiDoc; + /// + /// #[utoipa::path( + /// get, + /// path = "/users", + /// responses((status = 200, description = "List users")) + /// )] + /// async fn get_users() -> Json> { + /// Json(vec![]) + /// } + /// + /// let api_router = Router::new() + /// .route("/users", get(get_users)); + /// + /// server.add_openapi(api_router, ApiDoc::openapi()).await; + /// ``` + pub async fn add_openapi(&mut self, api_router: Router, openapi: utoipa::openapi::OpenApi) { + // Stocker le routeur API + let mut api_r = self.api_router.write().await; + *api_r = Some(api_router); + + // Ajouter Swagger UI + let swagger = SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", openapi); + + let mut r = self.router.write().await; + *r = std::mem::take(&mut *r).merge(swagger); + } + /// Démarre le serveur HTTP /// /// Lance le serveur sur le port configuré et met en place la gestion @@ -431,7 +453,18 @@ impl Server { /// ``` pub async fn start(&mut self) { let addr = SocketAddr::from(([0, 0, 0, 0], self.http_port)); - info!("Server {} running at [http://{}:{}](http://{}:{})", self.name, self.base_url, self.http_port, self.base_url, self.http_port); + info!( + "Server {} running at [http://{}:{}](http://{}:{})", + self.name, self.base_url, self.http_port, self.base_url, self.http_port + ); + + // Merger le routeur API si présent + let api_router = self.api_router.read().await; + if let Some(api_r) = api_router.as_ref() { + let mut r = self.router.write().await; + *r = std::mem::take(&mut *r).nest("/api", api_r.clone()); + } + drop(api_router); let router = self.router.clone(); @@ -499,7 +532,7 @@ impl ServerBuilder { Self { name: "PMO-Music-Server".to_string(), base_url: config.get_base_url(), - http_port: config.get_http_port() + http_port: config.get_http_port(), } } diff --git a/pmoupnp/src/state_variables/errors.rs b/pmoupnp/src/state_variables/errors.rs index 294cc1d0..050d4e9a 100644 --- a/pmoupnp/src/state_variables/errors.rs +++ b/pmoupnp/src/state_variables/errors.rs @@ -4,25 +4,25 @@ use thiserror::Error; pub enum StateVariableError { #[error("Conversion error: {0}")] ConversionError(String), - + #[error("Validation error: {0}")] ValidationError(String), - + #[error("Range error: {0}")] RangeError(String), - + #[error("Type error: {0}")] TypeError(String), - + #[error("Parse error: {0}")] ParseError(String), - + #[error("Event condition error: {0}")] EventConditionError(String), - + #[error("Arithmetic error: {0}")] ArithmeticError(String), - + #[error("Unknown error: {0}")] Unknown(String), } diff --git a/pmoupnp/src/state_variables/instance_methods.rs b/pmoupnp/src/state_variables/instance_methods.rs index 0e4da790..0e9093a6 100644 --- a/pmoupnp/src/state_variables/instance_methods.rs +++ b/pmoupnp/src/state_variables/instance_methods.rs @@ -2,10 +2,9 @@ use chrono::{DateTime, Utc}; use xmltree::Element; use crate::{ - state_variables::{StateVarInstance, StateVariable, UpnpVariable}, - variable_types::StateValue, - UpnpObject, - UpnpObjectType + UpnpObject, UpnpObjectType, + state_variables::{StateVarInstance, StateVariable, UpnpVariable}, + variable_types::StateValue, }; impl UpnpVariable for StateVarInstance { @@ -35,7 +34,7 @@ impl StateVarInstance { value: from.get_default(), old_value: from.get_default(), last_modified: Utc::now(), - last_notification: Utc::now() + last_notification: Utc::now(), } } @@ -54,5 +53,4 @@ impl StateVarInstance { pub fn last_modified(&self) -> DateTime { self.last_modified } - } diff --git a/pmoupnp/src/state_variables/mod.rs b/pmoupnp/src/state_variables/mod.rs index 33b9c6d0..f45fc51b 100644 --- a/pmoupnp/src/state_variables/mod.rs +++ b/pmoupnp/src/state_variables/mod.rs @@ -1,26 +1,33 @@ mod errors; -mod variable_trait; -mod variable_methods; mod instance_methods; +mod variable_methods; +mod variable_trait; -use std::{collections::HashMap, sync::{Arc, RwLock}}; +use std::{ + collections::HashMap, + sync::{Arc, RwLock}, +}; +pub use crate::state_variables::variable_trait::UpnpVariable; use chrono::{DateTime, Utc}; -pub use errors::{StateVariableError}; -pub use crate::state_variables::variable_trait::UpnpVariable; +pub use errors::StateVariableError; - -use crate::{value_ranges::ValueRange, variable_types::{StateValue, StateVarType}, UpnpObjectType}; +use crate::{ + UpnpObjectType, + value_ranges::ValueRange, + variable_types::{StateValue, StateVarType}, +}; /// Type pour les fonctions de condition d'événement pub type StateConditionFunc = Arc bool + Send + Sync>; /// Type pour les fonctions de parsing de valeurs depuis des chaînes -pub type StringValueParser = Arc Result + Send + Sync>; +pub type StringValueParser = + Arc Result + Send + Sync>; /// Type pour les fonctions de sérialisation de valeurs vers des chaînes -pub type ValueSerializer = Arc Result + Send + Sync>; - +pub type ValueSerializer = + Arc Result + Send + Sync>; pub struct StateVariable { object: UpnpObjectType, @@ -44,4 +51,4 @@ pub struct StateVarInstance { old_value: StateValue, last_modified: DateTime, last_notification: DateTime, -} \ No newline at end of file +} diff --git a/pmoupnp/src/state_variables/variable_methods.rs b/pmoupnp/src/state_variables/variable_methods.rs index a442fee2..a78ccd0c 100644 --- a/pmoupnp/src/state_variables/variable_methods.rs +++ b/pmoupnp/src/state_variables/variable_methods.rs @@ -20,7 +20,7 @@ impl UpnpObject for StateVariable { return &self.object; } -fn to_xml_element(&self) -> Element { + fn to_xml_element(&self) -> Element { // Création de l'élément racine let mut root = Element::new("stateVariable"); root.attributes.insert( @@ -65,11 +65,15 @@ fn to_xml_element(&self) -> Element { 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())); + 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())); + 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 { diff --git a/pmoupnp/src/state_variables/variable_trait.rs b/pmoupnp/src/state_variables/variable_trait.rs index 6925645a..a6c4e3a9 100644 --- a/pmoupnp/src/state_variables/variable_trait.rs +++ b/pmoupnp/src/state_variables/variable_trait.rs @@ -49,7 +49,7 @@ pub trait UpnpVariable { .clone() .unwrap_or_else(|| self.get_definition().as_state_var_type().default_value()) } - + fn has_allowed_values(&self) -> bool { return self.get_definition().allowed_values.read().unwrap().len() > 0; } diff --git a/pmoupnp/src/value_ranges/mod.rs b/pmoupnp/src/value_ranges/mod.rs index 389c87d3..7eaa0c4d 100644 --- a/pmoupnp/src/value_ranges/mod.rs +++ b/pmoupnp/src/value_ranges/mod.rs @@ -1,10 +1,9 @@ mod methods; - use crate::variable_types::StateValue; #[derive(Debug, Clone)] pub struct ValueRange { min: StateValue, max: StateValue, -} \ No newline at end of file +} diff --git a/pmoupnp/src/variable_types/cast.rs b/pmoupnp/src/variable_types/cast.rs index 89eac526..d9b6cfd3 100644 --- a/pmoupnp/src/variable_types/cast.rs +++ b/pmoupnp/src/variable_types/cast.rs @@ -1,9 +1,8 @@ -use crate::variable_types::{StateValue, StateVarType, StateValueError}; +use crate::variable_types::{StateValue, StateValueError, StateVarType}; use std::convert::TryFrom; impl StateValue { pub fn try_cast(&self, target: StateVarType) -> Result { - let source = StateVarType::from(self); // Identité (même type) @@ -14,18 +13,18 @@ impl StateValue { match (self, target) { (val, StateVarType::String) => Ok(StateValue::String(val.to_string())), - (_,StateVarType::UI1) => Ok(StateValue::UI1(u8::try_from(self)?)), - (_,StateVarType::UI2) => Ok(StateValue::UI2(u16::try_from(self)?)), - (_,StateVarType::UI4) => Ok(StateValue::UI4(u32::try_from(self)?)), - (_,StateVarType::I1) => Ok(StateValue::I1(i8::try_from(self)?)), - (_,StateVarType::I2) => Ok(StateValue::I2(i16::try_from(self)?)), - (_,StateVarType::I4) => Ok(StateValue::I4(i32::try_from(self)?)), - (_,StateVarType::Int) => Ok(StateValue::Int(i32::try_from(self)?)), + (_, StateVarType::UI1) => Ok(StateValue::UI1(u8::try_from(self)?)), + (_, StateVarType::UI2) => Ok(StateValue::UI2(u16::try_from(self)?)), + (_, StateVarType::UI4) => Ok(StateValue::UI4(u32::try_from(self)?)), + (_, StateVarType::I1) => Ok(StateValue::I1(i8::try_from(self)?)), + (_, StateVarType::I2) => Ok(StateValue::I2(i16::try_from(self)?)), + (_, StateVarType::I4) => Ok(StateValue::I4(i32::try_from(self)?)), + (_, StateVarType::Int) => Ok(StateValue::Int(i32::try_from(self)?)), - (_,StateVarType::R8) => Ok(StateValue::R8(f64::try_from(self)?)), - (_,StateVarType::Number) => Ok(StateValue::Number(f64::try_from(self)?)), - (_,StateVarType::Fixed14_4) => Ok(StateValue::Fixed14_4(f64::try_from(self)?)), - (_,StateVarType::R4) => Ok(StateValue::R4(f32::try_from(self)?)), + (_, StateVarType::R8) => Ok(StateValue::R8(f64::try_from(self)?)), + (_, StateVarType::Number) => Ok(StateValue::Number(f64::try_from(self)?)), + (_, StateVarType::Fixed14_4) => Ok(StateValue::Fixed14_4(f64::try_from(self)?)), + (_, StateVarType::R4) => Ok(StateValue::R4(f32::try_from(self)?)), // --- Pas encore implémenté pour les autres types --- (val, target) => Err(StateValueError::TypeError(format!( diff --git a/pmoupnp/src/variable_types/default_value.rs b/pmoupnp/src/variable_types/default_value.rs index 93ef4eb4..10795be8 100644 --- a/pmoupnp/src/variable_types/default_value.rs +++ b/pmoupnp/src/variable_types/default_value.rs @@ -24,20 +24,22 @@ impl StateVarType { StateVarType::BinBase64 => StateValue::BinBase64(String::new()), StateVarType::BinHex => StateValue::BinHex(String::new()), StateVarType::Date => StateValue::Date(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()), - StateVarType::DateTime => StateValue::DateTime(DateTime::from_timestamp(0, 0).unwrap().naive_utc().into()), - StateVarType::DateTimeTZ => StateValue::DateTimeTZ( - DateTime::from_naive_utc_and_offset( - DateTime::from_timestamp(0, 0).unwrap().naive_utc(), - FixedOffset::east_opt(0).unwrap()) - ), + StateVarType::DateTime => { + StateValue::DateTime(DateTime::from_timestamp(0, 0).unwrap().naive_utc().into()) + } + StateVarType::DateTimeTZ => { + StateValue::DateTimeTZ(DateTime::from_naive_utc_and_offset( + DateTime::from_timestamp(0, 0).unwrap().naive_utc(), + FixedOffset::east_opt(0).unwrap(), + )) + } StateVarType::Time => StateValue::Time(NaiveTime::from_hms_opt(0, 0, 0).unwrap()), - StateVarType::TimeTZ => StateValue::TimeTZ( - DateTime::from_naive_utc_and_offset( - DateTime::from_timestamp(0, 0).unwrap().naive_utc(), - FixedOffset::east_opt(0).unwrap()) - ), + StateVarType::TimeTZ => StateValue::TimeTZ(DateTime::from_naive_utc_and_offset( + DateTime::from_timestamp(0, 0).unwrap().naive_utc(), + FixedOffset::east_opt(0).unwrap(), + )), StateVarType::UUID => StateValue::UUID(Uuid::nil()), StateVarType::URI => StateValue::URI(Url::parse("http://localhost").unwrap()), } } -} \ No newline at end of file +} diff --git a/pmoupnp/src/variable_types/display_type.rs b/pmoupnp/src/variable_types/display_type.rs index 954af6c6..7794fd6d 100644 --- a/pmoupnp/src/variable_types/display_type.rs +++ b/pmoupnp/src/variable_types/display_type.rs @@ -2,7 +2,6 @@ use std::fmt; use crate::variable_types::StateVarType; - impl fmt::Display for StateVarType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = match self { diff --git a/pmoupnp/src/variable_types/display_value.rs b/pmoupnp/src/variable_types/display_value.rs index 41bedfc9..9cc18951 100644 --- a/pmoupnp/src/variable_types/display_value.rs +++ b/pmoupnp/src/variable_types/display_value.rs @@ -1,10 +1,9 @@ -use std::fmt; -use base64::engine::general_purpose; use base64::Engine; +use base64::engine::general_purpose; +use std::fmt; use crate::variable_types::StateValue; - impl fmt::Display for StateValue { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/pmoupnp/src/variable_types/errors.rs b/pmoupnp/src/variable_types/errors.rs index 5378cca1..04fc26e5 100644 --- a/pmoupnp/src/variable_types/errors.rs +++ b/pmoupnp/src/variable_types/errors.rs @@ -4,25 +4,25 @@ use thiserror::Error; pub enum StateValueError { #[error("Conversion error: {0}")] ConversionError(String), - + #[error("Validation error: {0}")] ValidationError(String), - + #[error("Range error: {0}")] RangeError(String), - + #[error("Type error: {0}")] TypeError(String), - + #[error("Parse error: {0}")] ParseError(String), - + #[error("Event condition error: {0}")] EventConditionError(String), - + #[error("Arithmetic error: {0}")] ArithmeticError(String), - + #[error("Unknown error: {0}")] Unknown(String), } diff --git a/pmoupnp/src/variable_types/fromstr.rs b/pmoupnp/src/variable_types/fromstr.rs index 7635b483..ecb1ee5a 100644 --- a/pmoupnp/src/variable_types/fromstr.rs +++ b/pmoupnp/src/variable_types/fromstr.rs @@ -1,6 +1,5 @@ -use std::str::FromStr; use crate::variable_types::StateVarType; - +use std::str::FromStr; impl FromStr for StateVarType { type Err = String; // Type d'erreur personnalisé @@ -30,7 +29,7 @@ impl FromStr for StateVarType { "time.tz" => Ok(StateVarType::TimeTZ), "uuid" => Ok(StateVarType::UUID), "uri" => Ok(StateVarType::URI), - _ => Err(format!("Type inconnu: {}", s)), + _ => Err(format!("Type inconnu: {}", s)), } } } diff --git a/pmoupnp/src/variable_types/mod.rs b/pmoupnp/src/variable_types/mod.rs index 4bd5e256..0d6c22cf 100644 --- a/pmoupnp/src/variable_types/mod.rs +++ b/pmoupnp/src/variable_types/mod.rs @@ -1,36 +1,36 @@ -mod type_methods; -mod value_methods; -mod type_trait; -mod value_trait; -mod fromstr; mod cast; +mod default_value; mod display_type; mod display_value; -mod default_value; mod errors; +mod fromstr; +mod type_methods; +mod type_trait; +mod value_methods; +mod value_trait; mod values_from_type; -mod values_from_u8; -mod values_from_u16; -mod values_from_u32; -mod values_from_i8; mod values_from_i16; mod values_from_i32; mod values_from_i64; +mod values_from_i8; +mod values_from_u16; +mod values_from_u32; +mod values_from_u8; mod values_from_f32; mod values_from_f64; -mod values_from_uri; -mod values_from_uuid; +mod values_from_datetime; mod values_from_naivedate; mod values_from_naivedatetime; mod values_from_naivetime; -mod values_from_datetime; +mod values_from_uri; +mod values_from_uuid; mod values_from_vec_u8; -use std::fmt::{Debug}; +use std::fmt::Debug; use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime}; use url::Url; @@ -92,5 +92,3 @@ pub enum StateValue { UUID(Uuid), URI(Url), } - - diff --git a/pmoupnp/src/variable_types/type_methods.rs b/pmoupnp/src/variable_types/type_methods.rs index e484c27a..2b819a4c 100644 --- a/pmoupnp/src/variable_types/type_methods.rs +++ b/pmoupnp/src/variable_types/type_methods.rs @@ -1,8 +1,8 @@ -use crate::variable_types::{type_trait::UpnpVarType, StateVarType}; +use crate::variable_types::{StateVarType, type_trait::UpnpVarType}; impl UpnpVarType for StateVarType { fn as_state_var_type(&self) -> StateVarType { - *self + *self } fn bit_size(&self) -> Option { @@ -62,10 +62,7 @@ impl UpnpVarType for StateVarType { fn is_float(&self) -> bool { matches!( self, - StateVarType::R4 - | StateVarType::R8 - | StateVarType::Number - | StateVarType::Fixed14_4 + StateVarType::R4 | StateVarType::R8 | StateVarType::Number | StateVarType::Fixed14_4 ) } @@ -74,10 +71,13 @@ impl UpnpVarType for StateVarType { } fn is_string(&self) -> bool { - matches!(self, StateVarType::String - | StateVarType::Char - | StateVarType::BinHex - | StateVarType::BinBase64) + matches!( + self, + StateVarType::String + | StateVarType::Char + | StateVarType::BinHex + | StateVarType::BinBase64 + ) } fn is_time(&self) -> bool { diff --git a/pmoupnp/src/variable_types/value_methods.rs b/pmoupnp/src/variable_types/value_methods.rs index 8f10bf90..d7ef8f67 100644 --- a/pmoupnp/src/variable_types/value_methods.rs +++ b/pmoupnp/src/variable_types/value_methods.rs @@ -2,7 +2,6 @@ use std::cmp::Ordering; use crate::variable_types::{StateValue, StateVarType, type_trait::UpnpVarType}; - impl UpnpVarType for StateValue { fn as_state_var_type(&self) -> StateVarType { StateVarType::from(self) // utilise ton From<&StateValue> existant diff --git a/pmoupnp/src/variable_types/value_trait.rs b/pmoupnp/src/variable_types/value_trait.rs index 23b0f392..87b9edac 100644 --- a/pmoupnp/src/variable_types/value_trait.rs +++ b/pmoupnp/src/variable_types/value_trait.rs @@ -1,2 +1 @@ -pub trait UpnpValue { -} \ No newline at end of file +pub trait UpnpValue {} diff --git a/pmoupnp/src/variable_types/values_from_datetime.rs b/pmoupnp/src/variable_types/values_from_datetime.rs index 0a5b8a6a..ee511664 100644 --- a/pmoupnp/src/variable_types/values_from_datetime.rs +++ b/pmoupnp/src/variable_types/values_from_datetime.rs @@ -1,6 +1,6 @@ -use std::convert::TryFrom; -use chrono::{DateTime,FixedOffset}; use crate::variable_types::{StateValue, StateValueError}; +use chrono::{DateTime, FixedOffset}; +use std::convert::TryFrom; impl TryFrom<&StateValue> for DateTime { type Error = StateValueError; @@ -9,9 +9,15 @@ impl TryFrom<&StateValue> for DateTime { match value { StateValue::DateTimeTZ(v) => Ok(v.clone()), StateValue::TimeTZ(v) => Ok(v.clone()), - StateValue::String(v) => DateTime::parse_from_rfc3339(v) - .map_err(|e| StateValueError::ParseError(format!("Cannot parse DateTimeTZ from string '{}': {}", v, e))), - _ => Err(StateValueError::TypeError("Cannot cast to DateTime".into())), + StateValue::String(v) => DateTime::parse_from_rfc3339(v).map_err(|e| { + StateValueError::ParseError(format!( + "Cannot parse DateTimeTZ from string '{}': {}", + v, e + )) + }), + _ => Err(StateValueError::TypeError( + "Cannot cast to DateTime".into(), + )), } } } @@ -25,9 +31,7 @@ impl TryFrom for DateTime { } impl From> for StateValue { - fn from(value: DateTime) -> Self { StateValue::DateTimeTZ(value) } } - diff --git a/pmoupnp/src/variable_types/values_from_f32.rs b/pmoupnp/src/variable_types/values_from_f32.rs index fc292c6c..dae0f0cc 100644 --- a/pmoupnp/src/variable_types/values_from_f32.rs +++ b/pmoupnp/src/variable_types/values_from_f32.rs @@ -2,7 +2,6 @@ use std::convert::TryFrom; use crate::variable_types::{StateValue, StateValueError}; - impl TryFrom<&StateValue> for f32 { type Error = StateValueError; @@ -12,12 +11,8 @@ impl TryFrom<&StateValue> for f32 { // --- Signed integers --- StateValue::I1(v) => Ok(*v as f32), StateValue::I2(v) => Ok(*v as f32), - StateValue::I4(v) - if *v > -MAX_EXACT && - *v < MAX_EXACT => Ok(*v as f32), - StateValue::Int(v) - if *v >= -MAX_EXACT && - *v <= MAX_EXACT as i32 => Ok(*v as f32), + StateValue::I4(v) if *v > -MAX_EXACT && *v < MAX_EXACT => Ok(*v as f32), + StateValue::Int(v) if *v >= -MAX_EXACT && *v <= MAX_EXACT as i32 => Ok(*v as f32), // --- Unsigned integers --- StateValue::UI1(v) => Ok(*v as f32), @@ -30,37 +25,38 @@ impl TryFrom<&StateValue> for f32 { // --- Floats --- StateValue::R4(v) => Ok(*v), // déjà un f32 StateValue::R8(v) - if ! v.is_finite() || - (*v <= f32::MAX as f64 && - *v >= f32::MIN as f64) => Ok(*v as f32), + if !v.is_finite() || (*v <= f32::MAX as f64 && *v >= f32::MIN as f64) => + { + Ok(*v as f32) + } StateValue::R8(_) => Err(StateValueError::TypeError( "Cannot cast R8 to f32: out of range".into(), )), StateValue::Number(v) - if ! v.is_finite() || - (*v <= f32::MAX as f64 && - *v >= f32::MIN as f64) => Ok(*v as f32), + if !v.is_finite() || (*v <= f32::MAX as f64 && *v >= f32::MIN as f64) => + { + Ok(*v as f32) + } StateValue::Number(_) => Err(StateValueError::TypeError( "Cannot cast Number to f32: out of range".into(), )), StateValue::Fixed14_4(v) - if ! v.is_finite() || - (*v <= f32::MAX as f64 && - *v >= f32::MIN as f64) => Ok(*v as f32), + if !v.is_finite() || (*v <= f32::MAX as f64 && *v >= f32::MIN as f64) => + { + Ok(*v as f32) + } StateValue::Fixed14_4(_) => Err(StateValueError::TypeError( "Cannot cast Fixed14_4 to f32: out of range".into(), )), StateValue::Boolean(v) => Ok((*v as i32) as Self), - StateValue::String(s) => s.parse::().map_err(|_| { - StateValueError::TypeError(format!("Cannot parse '{}' as f32", s)) - }), + StateValue::String(s) => s + .parse::() + .map_err(|_| StateValueError::TypeError(format!("Cannot parse '{}' as f32", s))), // --- Par défaut : erreur --- - _ => Err(StateValueError::TypeError( - "Cannot cast to f32".into(), - )), + _ => Err(StateValueError::TypeError("Cannot cast to f32".into())), } } } @@ -74,9 +70,7 @@ impl TryFrom for f32 { } impl From for StateValue { - fn from(value: f32) -> Self { StateValue::R4(value) } } - diff --git a/pmoupnp/src/variable_types/values_from_f64.rs b/pmoupnp/src/variable_types/values_from_f64.rs index 015621b9..cfb18419 100644 --- a/pmoupnp/src/variable_types/values_from_f64.rs +++ b/pmoupnp/src/variable_types/values_from_f64.rs @@ -26,14 +26,12 @@ impl TryFrom<&StateValue> for f64 { StateValue::Boolean(v) => Ok((*v as i32) as Self), - StateValue::String(s) => s.parse::().map_err(|_| { - StateValueError::TypeError(format!("Cannot parse '{}' as f64", s)) - }), + StateValue::String(s) => s + .parse::() + .map_err(|_| StateValueError::TypeError(format!("Cannot parse '{}' as f64", s))), // --- Par défaut : erreur --- - _ => Err(StateValueError::TypeError( - "Cannot cast to f64".into(), - )), + _ => Err(StateValueError::TypeError("Cannot cast to f64".into())), } } } diff --git a/pmoupnp/src/variable_types/values_from_i16.rs b/pmoupnp/src/variable_types/values_from_i16.rs index 5bc396fe..a99f4c74 100644 --- a/pmoupnp/src/variable_types/values_from_i16.rs +++ b/pmoupnp/src/variable_types/values_from_i16.rs @@ -1,6 +1,5 @@ use std::convert::TryFrom; - use crate::variable_types::{StateValue, StateValueError}; // Implémentations TryFrom pour types numériques @@ -12,17 +11,17 @@ impl TryFrom<&StateValue> for i16 { match value { StateValue::I1(v) => Ok(*v as i16), StateValue::I2(v) => Ok(*v), - StateValue::I4(v) if *v <= i16::MAX as i32 && *v >= i16::MIN as i32 => Ok(*v as i16), - StateValue::Int(v) if *v <= i16::MAX as i32 && *v >= i16::MIN as i32 => Ok(*v as i16), + StateValue::I4(v) if *v <= i16::MAX as i32 && *v >= i16::MIN as i32 => Ok(*v as i16), + StateValue::Int(v) if *v <= i16::MAX as i32 && *v >= i16::MIN as i32 => Ok(*v as i16), StateValue::UI1(v) => Ok(*v as i16), StateValue::UI2(v) if *v <= i16::MAX as u16 => Ok(*v as i16), StateValue::UI4(v) if *v <= i16::MAX as u32 => Ok(*v as i16), StateValue::Boolean(v) => Ok(*v as Self), - StateValue::String(s) => s.parse::().map_err(|_| { - StateValueError::TypeError(format!("Cannot parse '{}' as i16", s)) - }), + StateValue::String(s) => s + .parse::() + .map_err(|_| StateValueError::TypeError(format!("Cannot parse '{}' as i16", s))), _ => Err(StateValueError::TypeError("Cannot cast to i32".into())), } @@ -38,9 +37,7 @@ impl TryFrom for i16 { } impl From for StateValue { - fn from(value: i16) -> Self { StateValue::I2(value) } } - diff --git a/pmoupnp/src/variable_types/values_from_i32.rs b/pmoupnp/src/variable_types/values_from_i32.rs index ac944497..b561f0ae 100644 --- a/pmoupnp/src/variable_types/values_from_i32.rs +++ b/pmoupnp/src/variable_types/values_from_i32.rs @@ -2,7 +2,6 @@ use std::convert::TryFrom; use crate::variable_types::{StateValue, StateValueError}; - impl TryFrom<&StateValue> for i32 { type Error = StateValueError; @@ -17,12 +16,12 @@ impl TryFrom<&StateValue> for i32 { // non signés StateValue::UI1(v) => Ok(*v as i32), StateValue::UI2(v) => Ok(*v as i32), - StateValue::UI4(v) if *v <= i32::MAX as u32 =>Ok(*v as i32), + StateValue::UI4(v) if *v <= i32::MAX as u32 => Ok(*v as i32), StateValue::Boolean(v) => Ok(*v as Self), - StateValue::String(s) => s.parse::().map_err(|_| { - StateValueError::TypeError(format!("Cannot parse '{}' as i32", s)) - }), + StateValue::String(s) => s + .parse::() + .map_err(|_| StateValueError::TypeError(format!("Cannot parse '{}' as i32", s))), _ => Err(StateValueError::TypeError("Cannot cast to i32".into())), } @@ -38,9 +37,7 @@ impl TryFrom for i32 { } impl From for StateValue { - fn from(value: i32) -> Self { StateValue::I4(value) } } - diff --git a/pmoupnp/src/variable_types/values_from_i64.rs b/pmoupnp/src/variable_types/values_from_i64.rs index b4a92480..8550196d 100644 --- a/pmoupnp/src/variable_types/values_from_i64.rs +++ b/pmoupnp/src/variable_types/values_from_i64.rs @@ -1,5 +1,5 @@ -use std::convert::TryFrom; use crate::variable_types::{StateValue, StateValueError}; +use std::convert::TryFrom; impl TryFrom<&StateValue> for i64 { type Error = StateValueError; @@ -21,9 +21,9 @@ impl TryFrom<&StateValue> for i64 { StateValue::Boolean(v) => Ok(*v as i64), // chaîne → i64 - StateValue::String(s) => s.parse::().map_err(|_| { - StateValueError::TypeError(format!("Cannot parse '{}' as i64", s)) - }), + StateValue::String(s) => s + .parse::() + .map_err(|_| StateValueError::TypeError(format!("Cannot parse '{}' as i64", s))), _ => Err(StateValueError::TypeError("Cannot cast to i64".into())), } diff --git a/pmoupnp/src/variable_types/values_from_i8.rs b/pmoupnp/src/variable_types/values_from_i8.rs index 8831f507..ce15cab0 100644 --- a/pmoupnp/src/variable_types/values_from_i8.rs +++ b/pmoupnp/src/variable_types/values_from_i8.rs @@ -1,6 +1,5 @@ use std::convert::TryFrom; - use crate::variable_types::{StateValue, StateValueError}; // Implémentations TryFrom pour types numériques @@ -10,19 +9,19 @@ impl TryFrom<&StateValue> for i8 { fn try_from(value: &StateValue) -> Result { match value { - StateValue::I1(v) if *v >= 0 => Ok(*v as i8), - StateValue::I2(v) if *v <= i8::MAX as i16 && *v >= i8::MIN as i16 => Ok(*v as i8), - StateValue::I4(v) if *v <= i8::MAX as i32 && *v >= i8::MIN as i32=> Ok(*v as i8), - StateValue::Int(v) if *v <= i8::MAX as i32 && *v >= i8::MIN as i32=> Ok(*v as i8), + StateValue::I1(v) if *v >= 0 => Ok(*v as i8), + StateValue::I2(v) if *v <= i8::MAX as i16 && *v >= i8::MIN as i16 => Ok(*v as i8), + StateValue::I4(v) if *v <= i8::MAX as i32 && *v >= i8::MIN as i32 => Ok(*v as i8), + StateValue::Int(v) if *v <= i8::MAX as i32 && *v >= i8::MIN as i32 => Ok(*v as i8), StateValue::UI1(v) if *v <= i8::MAX as u8 => Ok(*v as i8), StateValue::UI2(v) if *v <= i8::MAX as u16 => Ok(*v as i8), StateValue::UI4(v) if *v <= i8::MAX as u32 => Ok(*v as i8), StateValue::Boolean(v) => Ok(*v as Self), - StateValue::String(s) => s.parse::().map_err(|_| { - StateValueError::TypeError(format!("Cannot parse '{}' as i8", s)) - }), + StateValue::String(s) => s + .parse::() + .map_err(|_| StateValueError::TypeError(format!("Cannot parse '{}' as i8", s))), _ => Err(StateValueError::TypeError("Cannot cast to i8".into())), } @@ -38,9 +37,7 @@ impl TryFrom for i8 { } impl From for StateValue { - fn from(value: i8) -> Self { StateValue::I1(value) } } - diff --git a/pmoupnp/src/variable_types/values_from_naivedate.rs b/pmoupnp/src/variable_types/values_from_naivedate.rs index 992a3931..db711533 100644 --- a/pmoupnp/src/variable_types/values_from_naivedate.rs +++ b/pmoupnp/src/variable_types/values_from_naivedate.rs @@ -1,6 +1,6 @@ -use std::convert::TryFrom; -use chrono::NaiveDate; use crate::variable_types::{StateValue, StateValueError}; +use chrono::NaiveDate; +use std::convert::TryFrom; impl TryFrom<&StateValue> for NaiveDate { type Error = StateValueError; @@ -8,9 +8,12 @@ impl TryFrom<&StateValue> for NaiveDate { fn try_from(value: &StateValue) -> Result { match value { StateValue::Date(v) => Ok(v.clone()), - StateValue::String(v) => NaiveDate::parse_from_str(v, "%Y-%m-%d") - .map_err(|e| StateValueError::ParseError(format!("Cannot parse Date from string '{}': {}", v, e))), - _ => Err(StateValueError::TypeError("Cannot cast to NaiveDate".into())), + StateValue::String(v) => NaiveDate::parse_from_str(v, "%Y-%m-%d").map_err(|e| { + StateValueError::ParseError(format!("Cannot parse Date from string '{}': {}", v, e)) + }), + _ => Err(StateValueError::TypeError( + "Cannot cast to NaiveDate".into(), + )), } } } @@ -24,9 +27,7 @@ impl TryFrom for NaiveDate { } impl From for StateValue { - fn from(value: NaiveDate) -> Self { StateValue::Date(value) } } - diff --git a/pmoupnp/src/variable_types/values_from_naivedatetime.rs b/pmoupnp/src/variable_types/values_from_naivedatetime.rs index 19dcba67..8395af91 100644 --- a/pmoupnp/src/variable_types/values_from_naivedatetime.rs +++ b/pmoupnp/src/variable_types/values_from_naivedatetime.rs @@ -1,6 +1,6 @@ -use std::convert::TryFrom; -use chrono::NaiveDateTime; use crate::variable_types::{StateValue, StateValueError}; +use chrono::NaiveDateTime; +use std::convert::TryFrom; impl TryFrom<&StateValue> for NaiveDateTime { type Error = StateValueError; @@ -9,8 +9,15 @@ impl TryFrom<&StateValue> for NaiveDateTime { match value { StateValue::DateTime(v) => Ok(v.clone()), StateValue::String(v) => NaiveDateTime::parse_from_str(&v, "%Y-%m-%dT%H:%M:%S") - .map_err(|e| StateValueError::ParseError(format!("Cannot parse DateTime from string '{}': {}", v, e))), - _ => Err(StateValueError::TypeError("Cannot cast to NaiveDateTime".into())), + .map_err(|e| { + StateValueError::ParseError(format!( + "Cannot parse DateTime from string '{}': {}", + v, e + )) + }), + _ => Err(StateValueError::TypeError( + "Cannot cast to NaiveDateTime".into(), + )), } } } @@ -24,7 +31,6 @@ impl TryFrom for NaiveDateTime { } impl From for StateValue { - fn from(value: NaiveDateTime) -> Self { StateValue::DateTime(value) } diff --git a/pmoupnp/src/variable_types/values_from_naivetime.rs b/pmoupnp/src/variable_types/values_from_naivetime.rs index a8de2594..1127898a 100644 --- a/pmoupnp/src/variable_types/values_from_naivetime.rs +++ b/pmoupnp/src/variable_types/values_from_naivetime.rs @@ -1,6 +1,6 @@ -use std::convert::TryFrom; -use chrono::NaiveTime; use crate::variable_types::{StateValue, StateValueError}; +use chrono::NaiveTime; +use std::convert::TryFrom; impl TryFrom<&StateValue> for NaiveTime { type Error = StateValueError; @@ -8,9 +8,12 @@ impl TryFrom<&StateValue> for NaiveTime { fn try_from(value: &StateValue) -> Result { match value { StateValue::Time(v) => Ok(v.clone()), - StateValue::String(v) => NaiveTime::parse_from_str(&v, "%H:%M:%S") - .map_err(|e| StateValueError::ParseError(format!("Cannot parse Time from string '{}': {}", v, e))), - _ => Err(StateValueError::TypeError("Cannot cast to NaiveTime".into())), + StateValue::String(v) => NaiveTime::parse_from_str(&v, "%H:%M:%S").map_err(|e| { + StateValueError::ParseError(format!("Cannot parse Time from string '{}': {}", v, e)) + }), + _ => Err(StateValueError::TypeError( + "Cannot cast to NaiveTime".into(), + )), } } } @@ -24,7 +27,6 @@ impl TryFrom for NaiveTime { } impl From for StateValue { - fn from(value: NaiveTime) -> Self { StateValue::Time(value) } diff --git a/pmoupnp/src/variable_types/values_from_u16.rs b/pmoupnp/src/variable_types/values_from_u16.rs index d835b7ee..1695dca3 100644 --- a/pmoupnp/src/variable_types/values_from_u16.rs +++ b/pmoupnp/src/variable_types/values_from_u16.rs @@ -1,7 +1,5 @@ - use std::convert::TryFrom; - use crate::variable_types::{StateValue, StateValueError}; // Implémentations TryFrom pour types numériques @@ -13,16 +11,16 @@ impl TryFrom<&StateValue> for u16 { match value { StateValue::UI1(v) => Ok(*v as Self), StateValue::UI2(v) => Ok(*v), - StateValue::UI4(v) if *v <= i16::MAX as u32 => Ok(*v as Self), - StateValue::I1(v) if *v >= 0 => Ok(*v as Self), + StateValue::UI4(v) if *v <= i16::MAX as u32 => Ok(*v as Self), + StateValue::I1(v) if *v >= 0 => Ok(*v as Self), StateValue::I2(v) if *v >= 0 => Ok(*v as Self), StateValue::I4(v) if *v >= 0 && *v <= u16::MAX as i32 => Ok(*v as Self), StateValue::Int(v) if *v >= 0 && *v <= u16::MAX as i32 => Ok(*v as Self), StateValue::Boolean(v) => Ok(*v as Self), - StateValue::String(s) => s.parse::().map_err(|_| { - StateValueError::TypeError(format!("Cannot parse '{}' as u16", s)) - }), + StateValue::String(s) => s + .parse::() + .map_err(|_| StateValueError::TypeError(format!("Cannot parse '{}' as u16", s))), _ => Err(StateValueError::TypeError("Cannot cast to u16".into())), } @@ -37,11 +35,8 @@ impl TryFrom for u16 { } } - impl From for StateValue { - fn from(value: u16) -> Self { StateValue::UI2(value) } } - diff --git a/pmoupnp/src/variable_types/values_from_u32.rs b/pmoupnp/src/variable_types/values_from_u32.rs index b94d91d3..d28c9bdb 100644 --- a/pmoupnp/src/variable_types/values_from_u32.rs +++ b/pmoupnp/src/variable_types/values_from_u32.rs @@ -1,6 +1,5 @@ use std::convert::TryFrom; - use crate::variable_types::{StateValue, StateValueError}; impl TryFrom<&StateValue> for u32 { @@ -10,16 +9,16 @@ impl TryFrom<&StateValue> for u32 { match value { StateValue::UI1(v) => Ok(*v as Self), StateValue::UI2(v) => Ok(*v as Self), - StateValue::UI4(v) => Ok(*v), + StateValue::UI4(v) => Ok(*v), StateValue::I1(v) if *v >= 0 => Ok(*v as Self), StateValue::I2(v) if *v >= 0 => Ok(*v as Self), StateValue::I4(v) if *v >= 0 => Ok(*v as Self), StateValue::Int(v) if *v >= 0 => Ok(*v as Self), StateValue::Boolean(v) => Ok(*v as Self), - StateValue::String(s) => s.parse::().map_err(|_| { - StateValueError::TypeError(format!("Cannot parse '{}' as u32", s)) - }), + StateValue::String(s) => s + .parse::() + .map_err(|_| StateValueError::TypeError(format!("Cannot parse '{}' as u32", s))), _ => Err(StateValueError::TypeError("Cannot cast to u32".into())), } @@ -34,12 +33,8 @@ impl TryFrom for u32 { } } - - impl From for StateValue { - fn from(value: u32) -> Self { StateValue::UI4(value) } } - diff --git a/pmoupnp/src/variable_types/values_from_u8.rs b/pmoupnp/src/variable_types/values_from_u8.rs index 8899bde2..f8ced643 100644 --- a/pmoupnp/src/variable_types/values_from_u8.rs +++ b/pmoupnp/src/variable_types/values_from_u8.rs @@ -1,6 +1,5 @@ use std::convert::TryFrom; - use crate::variable_types::{StateValue, StateValueError}; // Implémentations TryFrom pour types numériques @@ -12,16 +11,16 @@ impl TryFrom<&StateValue> for u8 { match value { StateValue::UI1(v) => Ok(*v), StateValue::UI2(v) if *v <= u8::MAX as u16 => Ok(*v as u8), - StateValue::UI4(v) if *v <= i8::MAX as u32 => Ok(*v as u8), + StateValue::UI4(v) if *v <= i8::MAX as u32 => Ok(*v as u8), StateValue::I1(v) if *v >= 0 => Ok(*v as u8), StateValue::I2(v) if *v >= 0 && *v <= u8::MAX as i16 => Ok(*v as u8), StateValue::I4(v) if *v >= 0 && *v <= u8::MAX as i32 => Ok(*v as u8), StateValue::Int(v) if *v >= 0 && *v <= u8::MAX as i32 => Ok(*v as u8), StateValue::Boolean(v) => Ok(*v as Self), - StateValue::String(s) => s.parse::().map_err(|_| { - StateValueError::TypeError(format!("Cannot parse '{}' as u8", s)) - }), + StateValue::String(s) => s + .parse::() + .map_err(|_| StateValueError::TypeError(format!("Cannot parse '{}' as u8", s))), _ => Err(StateValueError::TypeError("Cannot cast to u8".into())), } @@ -37,9 +36,7 @@ impl TryFrom for u8 { } impl From for StateValue { - fn from(value: u8) -> Self { StateValue::UI1(value) } } - diff --git a/pmoupnp/src/variable_types/values_from_uri.rs b/pmoupnp/src/variable_types/values_from_uri.rs index a717862c..cf1a1977 100644 --- a/pmoupnp/src/variable_types/values_from_uri.rs +++ b/pmoupnp/src/variable_types/values_from_uri.rs @@ -13,8 +13,7 @@ impl TryFrom for Url { // Si c'est une String, on tente un parse StateValue::String(v) => { - Url::parse(&v) - .map_err(|_| StateValueError::TypeError("Invalid URI string".into())) + Url::parse(&v).map_err(|_| StateValueError::TypeError("Invalid URI string".into())) } // Autres types : erreur @@ -24,7 +23,6 @@ impl TryFrom for Url { } impl From for StateValue { - fn from(value: Url) -> Self { StateValue::URI(value) } diff --git a/pmoupnp/src/variable_types/values_from_uuid.rs b/pmoupnp/src/variable_types/values_from_uuid.rs index 3bf78032..cd0b1369 100644 --- a/pmoupnp/src/variable_types/values_from_uuid.rs +++ b/pmoupnp/src/variable_types/values_from_uuid.rs @@ -12,10 +12,8 @@ impl TryFrom for Uuid { StateValue::UUID(v) => Ok(v), // Si c'est une String, on tente un parse - StateValue::String(v) => { - Uuid::parse_str(&v) - .map_err(|_| StateValueError::TypeError("Invalid UUID string".into())) - } + StateValue::String(v) => Uuid::parse_str(&v) + .map_err(|_| StateValueError::TypeError("Invalid UUID string".into())), // Autres types : erreur _ => Err(StateValueError::TypeError("Cannot cast to Uuid".into())), @@ -24,7 +22,6 @@ impl TryFrom for Uuid { } impl From for StateValue { - fn from(value: Uuid) -> Self { StateValue::UUID(value) } diff --git a/pmoupnp/src/variable_types/values_from_vec_u8.rs b/pmoupnp/src/variable_types/values_from_vec_u8.rs index 776b395d..3ea60848 100644 --- a/pmoupnp/src/variable_types/values_from_vec_u8.rs +++ b/pmoupnp/src/variable_types/values_from_vec_u8.rs @@ -1,6 +1,6 @@ -use std::convert::TryFrom; use crate::variable_types::{StateValue, StateValueError}; -use base64::{engine::general_purpose::STANDARD, Engine as _}; +use base64::{Engine as _, engine::general_purpose::STANDARD}; +use std::convert::TryFrom; impl TryFrom<&StateValue> for Vec { type Error = StateValueError; @@ -8,10 +8,11 @@ impl TryFrom<&StateValue> for Vec { fn try_from(value: &StateValue) -> Result { match value { // Déjà un vecteur binaire - StateValue::BinBase64(v) => STANDARD.decode(v).map_err( - |e| StateValueError::ParseError(format!("Base64 decode error: {}", e))), - StateValue::BinHex(v) => hex::decode(v).map_err( - |e| StateValueError::ParseError(format!("BinHex decode error: {}", e))), + StateValue::BinBase64(v) => STANDARD + .decode(v) + .map_err(|e| StateValueError::ParseError(format!("Base64 decode error: {}", e))), + StateValue::BinHex(v) => hex::decode(v) + .map_err(|e| StateValueError::ParseError(format!("BinHex decode error: {}", e))), // Conversion depuis une chaîne encodée StateValue::String(s) => { diff --git a/pmoutils/src/ip_utils.rs b/pmoutils/src/ip_utils.rs index 5e7aa671..f16c9bae 100644 --- a/pmoutils/src/ip_utils.rs +++ b/pmoutils/src/ip_utils.rs @@ -1,5 +1,5 @@ -use std::net::UdpSocket; use get_if_addrs::get_if_addrs; +use std::net::UdpSocket; pub fn guess_local_ip() -> String { // On tente de deviner l'IP locale @@ -17,7 +17,6 @@ pub fn guess_local_ip() -> String { } } - fn list_all_ips() -> std::collections::HashMap> { let mut result = std::collections::HashMap::new(); @@ -28,13 +27,17 @@ fn list_all_ips() -> std::collections::HashMap> { continue; } if ip.is_ipv4() { - result.entry(iface.name) - .or_insert_with(Vec::new) - .push(ip.to_string()); + result + .entry(iface.name) + .or_insert_with(Vec::new) + .push(ip.to_string()); } } } else { - result.insert("error".to_string(), vec!["Failed to get interfaces".to_string()]); + result.insert( + "error".to_string(), + vec!["Failed to get interfaces".to_string()], + ); } result diff --git a/pmoutils/src/lib.rs b/pmoutils/src/lib.rs index 548e0ba7..d5108408 100644 --- a/pmoutils/src/lib.rs +++ b/pmoutils/src/lib.rs @@ -1,3 +1,3 @@ mod ip_utils; -pub use ip_utils::guess_local_ip; \ No newline at end of file +pub use ip_utils::guess_local_ip;