1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! Easy HTTP configuration library.
//!
//! `choices` is a library that lets you expose your application's configuration
//! over HTTP with a simple struct!
//!
//! ## Examples
//!
//! Given the following code:
//!
//! ```no_run
//! use choices::Choices;
//! use lazy_static::lazy_static;
//! use std::sync::{Arc, Mutex};
//!
//! #[derive(Choices)]
//! struct Config {
//!     debug: bool,
//!     id: Option<i32>,
//!     log_file: String,
//! }
//!
//! lazy_static! {
//!     static ref CONFIG: Arc<Mutex<Config>> = {
//!         Arc::new(Mutex::new(Config {
//!             debug: false,
//!             id: Some(3),
//!             log_file: "log.txt".to_string()
//!         }))
//!     };
//! }
//!
//! #[tokio::main]
//! async fn main() {
//!     CONFIG.run((std::net::Ipv4Addr::LOCALHOST, 8081)).await;
//! }
//! ```
//!
//! You can see all configuration fields at `localhost:8081/config`
//! and the individual fields' values at `localhost:8081/config/<field name>`\
//! A field's value can be changed with a `PUT`, for instance
//! `curl -X PUT localhost:8081/config/debug -d "true"`.
//!
//! More examples on [github](https://github.com/Trisfald/choices/blob/master/examples/).
//!
//! ## Documentation
//! Check out the documentation on
//! [github](https://github.com/Trisfald/choices/blob/master/documentation.md).

#![forbid(unsafe_code)]
#![deny(missing_docs)]

#[doc(hidden)]
pub use choices_derive::*;

/// Re-export of `bytes`
pub mod bytes {
    pub use bytes::*;
}

/// Re-export of `warp`
pub mod warp {
    pub use warp::*;
}

#[cfg(feature = "json")]
/// Re-export of `serde_json`
pub mod serde_json {
    pub use serde_json::*;
}

#[doc(hidden)]
pub use async_trait::*;

pub mod error;
pub use crate::error::{ChoicesError, ChoicesResult};

pub mod serde;
pub use crate::serde::{ChoicesInput, ChoicesOutput};

use std::net::SocketAddr;
use std::sync::{Arc, Mutex, RwLock};

/// A trait to manage the http server responsible for the configuration.
#[self::async_trait]
pub trait Choices {
    /// Starts the configuration http server on the chosen address.
    async fn run<T: Into<SocketAddr> + Send>(&'static self, addr: T);

    #[doc(hidden)]
    async fn run_mutable<T: Into<SocketAddr> + Send>(_: Arc<Mutex<Self>>, _: T) {
        unimplemented!()
    }

    #[doc(hidden)]
    async fn run_mutable_rw<T: Into<SocketAddr> + Send>(_: Arc<RwLock<Self>>, _: T)
    where
        Self: Sync,
    {
        unimplemented!()
    }
}

#[self::async_trait]
impl<C: Choices + Send> Choices for Arc<Mutex<C>> {
    async fn run<T: Into<SocketAddr> + Send>(&'static self, addr: T) {
        C::run_mutable(self.clone(), addr).await;
    }
}

#[self::async_trait]
impl<C: Choices + Send + Sync> Choices for Arc<RwLock<C>> {
    async fn run<T: Into<SocketAddr> + Send>(&'static self, addr: T) {
        C::run_mutable_rw(self.clone(), addr).await;
    }
}