domain/zonetree/
zone.rs

1use std::boxed::Box;
2use std::fmt::Debug;
3use std::future::Future;
4use std::pin::Pin;
5use std::sync::Arc;
6
7use crate::base::iana::Class;
8use crate::zonefile::inplace;
9
10use super::error::{RecordError, ZoneErrors};
11use super::in_memory::ZoneBuilder;
12use super::traits::WritableZone;
13use super::types::StoredName;
14use super::{parsed, ReadableZone, ZoneStore};
15
16/// A single DNS zone.
17///
18/// # Abstract backing store
19///
20/// The actual backing store implementation used by a [`Zone`] is determined
21/// by the [`ZoneStore`] impl it wraps. In this way one can treat in-memory
22/// zone implementations and other backing store types (for example a database
23/// backed zone) in the same way, and even to store zones with different
24/// backing stores together in the same [`ZoneTree`].
25///
26/// # Layering functionality
27///
28/// The functionality of [`Zone`]s can be extended by creating a [`ZoneStore`]
29/// implementation that wraps another [`ZoneStore`] implementation with the
30/// purpose of wrapping the original zone with additional state and
31/// functionality.
32///
33/// This could be used to detect changes to the [`Zone`] via your own
34/// [`WritableZone`] impl e.g. to sign it or persist it, or to detect updated
35/// SOA timers, and so on.
36///
37/// To layer [`ZoneStore`] implementations on top of one another, use
38/// [`Zone::into_inner()`] to obtain backing store implementation of a
39/// [`Zone`] then store that (via [`Arc<dyn ZoneStore`]) in a wrapper type
40/// that itself implements [`ZoneStore`], and then use [`Zone::new()`] to
41/// create a new [`Zone`] based on the outer backing store impl.
42///
43/// Then to gain access to the additional functionality and state use
44/// [`ZoneStore::as_any()`] and attempt to [`Any::downcast()`] to a
45/// [`ZoneStore`] implementing type that was used earlier.
46#[derive(Clone, Debug)]
47pub struct Zone {
48    store: Arc<dyn ZoneStore>,
49}
50
51impl Zone {
52    /// Creates a new [`Zone`] instance with the given data.
53    pub fn new(data: impl ZoneStore + 'static) -> Self {
54        Zone {
55            store: Arc::new(data),
56        }
57    }
58
59    /// Exchange this [`Zone`] wrapper for the actual underlying backing store
60    /// implementation.
61    pub fn into_inner(self) -> Arc<dyn ZoneStore> {
62        self.store
63    }
64
65    /// Gets the CLASS of this zone.
66    pub fn class(&self) -> Class {
67        self.store.class()
68    }
69
70    /// Gets the apex name of this zone.
71    pub fn apex_name(&self) -> &StoredName {
72        self.store.apex_name()
73    }
74
75    /// Gets a read interface to this zone.
76    pub fn read(&self) -> Box<dyn ReadableZone> {
77        self.store.clone().read()
78    }
79
80    /// Gets a write interface to this zone.
81    pub fn write(
82        &self,
83    ) -> Pin<Box<dyn Future<Output = Box<dyn WritableZone>> + Send + Sync>>
84    {
85        self.store.clone().write()
86    }
87}
88
89impl AsRef<dyn ZoneStore> for Zone {
90    fn as_ref(&self) -> &dyn ZoneStore {
91        self.store.as_ref()
92    }
93}
94
95//--- TryFrom<inplace::Zonefile>
96
97impl TryFrom<inplace::Zonefile> for Zone {
98    type Error = ZoneErrors<RecordError>;
99
100    fn try_from(source: inplace::Zonefile) -> Result<Self, Self::Error> {
101        parsed::Zonefile::try_from(source)?.try_into()
102    }
103}
104
105//--- TryFrom<ZoneBuilder>
106
107impl From<ZoneBuilder> for Zone {
108    fn from(builder: ZoneBuilder) -> Self {
109        builder.build()
110    }
111}
112
113//--- TryFrom<parsed::Zonefile>
114
115impl TryFrom<parsed::Zonefile> for Zone {
116    type Error = ZoneErrors<RecordError>;
117
118    fn try_from(source: parsed::Zonefile) -> Result<Self, Self::Error> {
119        Ok(Zone::from(ZoneBuilder::try_from(source).map_err(
120            |errors| {
121                let mut new_errors = Self::Error::default();
122                for (name, err) in errors {
123                    new_errors
124                        .add_error(name, RecordError::InvalidRecord(err))
125                }
126                new_errors
127            },
128        )?))
129    }
130}