mc_repack_core/
cfg.rs

1use std::sync::{Arc, RwLock};
2
3use state::TypeMap;
4
5/// A configuration map.
6pub struct ConfigMap(Arc<RwLock<TypeMap![Sync + Send]>>);
7impl ConfigMap {
8    /// Fetches a configuration holder for a type that accepts stored config.
9    /// # Panics
10    /// Panics if the read-write lock is poisoned.
11    #[must_use]
12    pub fn fetch<AC: AcceptsConfig>(&self) -> ConfigHolder<AC> {
13        let ch = self.0.read().unwrap().try_get::<ConfigHolder<AC>>().cloned();
14        ch.map_or_else(move || {
15            let cfg = ConfigHolder(Arc::new(AC::Cfg::default()));
16            self.0.write().unwrap().set::<ConfigHolder<AC>>(ConfigHolder::clone(&cfg));
17            cfg
18        }, |cfg| cfg)
19    }
20
21    /// Sets a config for a type that accepts it. It should be used before any configurable operation.
22    /// # Panics
23    /// Panics if the read-write lock is poisoned.
24    pub fn set<AC: AcceptsConfig>(&self, cfg: AC::Cfg) {
25        self.0.write().unwrap().set::<ConfigHolder<AC>>(ConfigHolder(Arc::new(cfg)));
26    }
27}
28impl Clone for ConfigMap {
29    fn clone(&self) -> Self {
30        Self(self.0.clone())
31    }
32}
33impl Default for ConfigMap {
34    fn default() -> Self {
35        Self(Arc::new(RwLock::new(<TypeMap![Sync + Send]>::new())))
36    }
37}
38
39/// A type that accepts a stored config. It usually is an empty enum.
40pub trait AcceptsConfig: 'static {
41    /// A configuration type.
42    type Cfg: 'static + Send + Sync + Default;
43}
44
45/// A configuration holder. Any type that wants to use the config must implement methods for config holder.
46pub struct ConfigHolder<AC: AcceptsConfig>(Arc<AC::Cfg>);
47impl<AC: AcceptsConfig> Clone for ConfigHolder<AC> {
48    fn clone(&self) -> Self {
49        Self(self.0.clone())
50    }
51}
52impl<AC: AcceptsConfig> std::ops::Deref for ConfigHolder<AC> {
53    type Target = AC::Cfg;
54    fn deref(&self) -> &Self::Target {
55        &self.0
56    }
57}
58
59macro_rules! acfg {
60    ($(#[doc = $doc:expr])? $ac:ident : $cfg:ty) => {
61        $(#[doc = $doc])?
62        /// This empty enum type should not be used without [`ConfigHolder`].
63        pub enum $ac {}
64        impl crate::cfg::AcceptsConfig for $ac {
65            type Cfg = $cfg;
66        }
67    };
68}
69pub(crate) use acfg;
70
71#[cfg(feature = "_any-zopfli")]
72/// Universal configuration for Zopfli.
73/// It determines if Zopfli will be enabled and how many iterations will be used.
74#[cfg_attr(feature = "serde-cfg", derive(serde::Serialize, serde::Deserialize), serde(untagged))]
75pub enum CfgZopfli {
76    /// A switch value (`true` or `false`).
77    /// If it is enabled then Zopfli will be enabled with 10 iterations by default.
78    Switch(bool),
79    /// An iteration count. If it is 0 then Zopfli will be disabled.
80    Iter(u8)
81}
82#[cfg(feature = "_any-zopfli")]
83impl Default for CfgZopfli {
84    fn default() -> Self {
85        Self::Switch(false)
86    }
87}
88
89#[cfg(feature = "_any-zopfli")]
90impl CfgZopfli {
91    /// Returns the iteration count based on its state.
92    #[inline]
93    #[must_use]
94    pub const fn iter_count(&self) -> Option<std::num::NonZeroU8> {
95        match self {
96            Self::Switch(false) => None,
97            Self::Iter(x) => std::num::NonZeroU8::new(*x),
98            Self::Switch(true) => std::num::NonZeroU8::new(10)
99        }
100    }
101}
102