config derive attrs: Make builders serde, and validated structs not

* Builders additionally derive: Debug, Serialize, Deserialize.

 * Validated structs no longer derive: Serialize, Deserialize
   and all related attributes deleted.

 * As a consequence, all the `#[serde(deny_unknown_fields)]`
   are gone.  That means that right now unknown fields are totally
   ignored.  This is good for compatibility but poor for useability.
   Doing something better here is arti#417, in progress.

 * As a consequence, delete tor_dirmgr::retry::default_parallelism.
   (The default value was already duplicated into a builder attr.)
This commit is contained in:
Ian Jackson 2022-05-04 17:45:25 +01:00
parent 6a39f9d8da
commit d47e94b459
11 changed files with 56 additions and 98 deletions

View File

@ -13,7 +13,7 @@
use derive_builder::Builder;
use derive_more::AsRef;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf;
@ -45,17 +45,15 @@ pub mod dir {
/// You can replace this configuration on a running Arti client. Doing so will
/// affect new streams and requests, but will have no effect on existing streams
/// and requests.
#[derive(Debug, Clone, Builder, Deserialize, Eq, PartialEq)]
#[derive(Debug, Clone, Builder, Eq, PartialEq)]
#[builder(build_fn(error = "ConfigBuildError"))]
#[builder(derive(Deserialize))]
#[serde(deny_unknown_fields)]
#[builder(derive(Debug, Serialize, Deserialize))]
pub struct ClientAddrConfig {
/// Should we allow attempts to make Tor connections to local addresses?
///
/// This option is off by default, since (by default) Tor exits will
/// always reject connections to such addresses.
#[builder(default)]
#[serde(default)]
pub(crate) allow_local_addrs: bool,
}
@ -67,29 +65,25 @@ pub struct ClientAddrConfig {
/// You can replace this configuration on a running Arti client. Doing so will
/// affect new streams and requests, but will have no effect on existing streams
/// and requests—even those that are currently waiting.
#[derive(Debug, Clone, Builder, Deserialize, Eq, PartialEq)]
#[derive(Debug, Clone, Builder, Eq, PartialEq)]
#[builder(build_fn(error = "ConfigBuildError"))]
#[builder(derive(Deserialize))]
#[serde(deny_unknown_fields)]
#[builder(derive(Debug, Serialize, Deserialize))]
#[non_exhaustive]
pub struct StreamTimeoutConfig {
/// How long should we wait before timing out a stream when connecting
/// to a host?
#[builder(default = "default_connect_timeout()")]
#[serde(with = "humantime_serde", default = "default_connect_timeout")]
#[builder_field_attr(serde(with = "humantime_serde::option"))]
pub(crate) connect_timeout: Duration,
/// How long should we wait before timing out when resolving a DNS record?
#[builder(default = "default_dns_resolve_timeout()")]
#[serde(with = "humantime_serde", default = "default_dns_resolve_timeout")]
#[builder_field_attr(serde(with = "humantime_serde::option"))]
pub(crate) resolve_timeout: Duration,
/// How long should we wait before timing out when resolving a DNS
/// PTR record?
#[builder(default = "default_dns_resolve_ptr_timeout()")]
#[serde(with = "humantime_serde", default = "default_dns_resolve_ptr_timeout")]
#[builder_field_attr(serde(with = "humantime_serde::option"))]
pub(crate) resolve_ptr_timeout: Duration,
}
@ -155,18 +149,15 @@ fn default_dns_resolve_ptr_timeout() -> Duration {
/// This section is for read/write storage.
///
/// You cannot change this section on a running Arti client.
#[derive(Deserialize, Debug, Clone, Builder, Eq, PartialEq)]
#[serde(deny_unknown_fields)]
#[derive(Debug, Clone, Builder, Eq, PartialEq)]
#[builder(build_fn(error = "ConfigBuildError"))]
#[builder(derive(Deserialize))]
#[builder(derive(Debug, Serialize, Deserialize))]
pub struct StorageConfig {
/// Location on disk for cached directory information.
#[builder(setter(into), default = "default_cache_dir()")]
#[serde(default = "default_cache_dir")]
cache_dir: CfgPath,
/// Location on disk for less-sensitive persistent state information.
#[builder(setter(into), default = "default_state_dir()")]
#[serde(default = "default_state_dir")]
state_dir: CfgPath,
}
@ -240,7 +231,7 @@ impl StorageConfig {
/// [#285]: https://gitlab.torproject.org/tpo/core/arti/-/issues/285
#[derive(Clone, Builder, Debug, Eq, PartialEq, AsRef)]
#[builder(build_fn(error = "ConfigBuildError"))]
#[builder(derive(Deserialize))]
#[builder(derive(Serialize, Deserialize, Debug))]
pub struct TorClientConfig {
/// Information about the Tor network we want to connect to.
#[builder(sub_builder)]

View File

@ -3,7 +3,7 @@
// (Thia module is called `cfg` to avoid name clash with the `config` crate, which we use.)
use derive_builder::Builder;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use arti_client::config::TorClientConfigBuilder;
use arti_client::TorClientConfig;
@ -12,10 +12,9 @@ use tor_config::ConfigBuildError;
use crate::{LoggingConfig, LoggingConfigBuilder};
/// Structure to hold our application configuration options
#[derive(Deserialize, Debug, Default, Clone, Builder, Eq, PartialEq)]
#[serde(deny_unknown_fields)]
#[derive(Debug, Default, Clone, Builder, Eq, PartialEq)]
#[builder(build_fn(error = "ConfigBuildError"))]
#[builder(derive(Deserialize))]
#[builder(derive(Debug, Serialize, Deserialize))]
pub struct ApplicationConfig {
/// If true, we should watch our configuration files for changes, and reload
/// our configuration when they change.
@ -24,7 +23,6 @@ pub struct ApplicationConfig {
/// directory holding our configuration files changes its identity (because
/// an intermediate symlink is changed, because the directory is removed and
/// recreated, or for some other reason).
#[serde(default)]
#[builder(default)]
pub(crate) watch_configuration: bool,
}
@ -33,7 +31,7 @@ pub struct ApplicationConfig {
#[derive(Deserialize, Debug, Clone, Builder, Eq, PartialEq)]
#[serde(deny_unknown_fields)]
#[builder(build_fn(error = "ConfigBuildError"))]
#[builder(derive(Deserialize))]
#[builder(derive(Debug, Serialize, Deserialize))]
pub struct ProxyConfig {
/// Port to listen on (at localhost) for incoming SOCKS
/// connections.
@ -68,15 +66,13 @@ impl ProxyConfig {
/// Configuration for system resources used by Tor.
///
/// You cannot change this section on a running Arti client.
#[derive(Deserialize, Debug, Clone, Builder, Eq, PartialEq)]
#[serde(deny_unknown_fields)]
#[derive(Debug, Clone, Builder, Eq, PartialEq)]
#[builder(build_fn(error = "ConfigBuildError"))]
#[builder(derive(Deserialize))]
#[builder(derive(Debug, Serialize, Deserialize))]
#[non_exhaustive]
pub struct SystemConfig {
/// Maximum number of file descriptors we should launch with
#[builder(setter(into), default = "default_max_files()")]
#[serde(default = "default_max_files")]
pub(crate) max_files: u64,
}
@ -113,7 +109,7 @@ impl SystemConfig {
/// NOTE: These are NOT the final options or their final layout. Expect NO
/// stability here.
#[derive(Debug, Builder, Clone, Eq, PartialEq, Default)]
#[builder(derive(Deserialize))]
#[builder(derive(Serialize, Deserialize, Debug))]
#[builder(build_fn(error = "ConfigBuildError"))]
pub struct ArtiConfig {
/// Configuration for application behavior.

View File

@ -2,7 +2,7 @@
use anyhow::{anyhow, Context, Result};
use derive_builder::Builder;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use std::path::Path;
use std::str::FromStr;
use tor_config::{define_list_builder_accessors, define_list_builder_helper};
@ -14,11 +14,10 @@ use tracing_subscriber::prelude::*;
use tracing_subscriber::{filter::Targets, fmt, registry, Layer};
/// Structure to hold our logging configuration options
#[derive(Deserialize, Debug, Clone, Builder, Eq, PartialEq)]
#[serde(deny_unknown_fields)]
#[derive(Debug, Clone, Builder, Eq, PartialEq)]
#[non_exhaustive] // TODO(nickm) remove public elements when I revise this.
#[builder(build_fn(error = "ConfigBuildError"))]
#[builder(derive(Deserialize))]
#[builder(derive(Debug, Serialize, Deserialize))]
pub struct LoggingConfig {
/// Filtering directives that determine tracing levels as described at
/// <https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/targets/struct.Targets.html#impl-FromStr>
@ -26,21 +25,18 @@ pub struct LoggingConfig {
/// You can override this setting with the -l, --log-level command line parameter.
///
/// Example: "info,tor_proto::channel=trace"
#[serde(default = "default_console_filter")]
#[builder(default = "default_console_filter()", setter(into, strip_option))]
console: Option<String>,
/// Filtering directives for the journald logger.
///
/// Only takes effect if Arti is built with the `journald` filter.
#[serde(default)]
#[builder(default, setter(into, strip_option))]
journald: Option<String>,
/// Configuration for one or more logfiles.
///
/// The default is not to log to any files.
#[serde(default)]
#[builder_field_attr(serde(default))]
#[builder(sub_builder, setter(custom))]
files: LogfileListConfig,
@ -83,12 +79,11 @@ define_list_builder_accessors! {
}
/// Configuration information for an (optionally rotating) logfile.
#[derive(Deserialize, Debug, Builder, Clone, Eq, PartialEq)]
#[builder(derive(Deserialize))]
#[derive(Debug, Builder, Clone, Eq, PartialEq)]
#[builder(derive(Debug, Serialize, Deserialize))]
#[builder(build_fn(error = "ConfigBuildError"))]
pub struct LogfileConfig {
/// How often to rotate the file?
#[serde(default)]
#[builder(default)]
rotate: LogRotation,
/// Where to write the files?

View File

@ -9,7 +9,7 @@ use tor_config::{define_list_builder_accessors, define_list_builder_helper, Conf
use tor_guardmgr::fallback::FallbackList;
use derive_builder::Builder;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use std::time::Duration;
@ -22,17 +22,15 @@ use std::time::Duration;
/// paths that are constructed in the future, and prevents requests from being
/// attached to existing circuits, if the configuration has become more
/// restrictive.
#[derive(Debug, Clone, Builder, Deserialize, Eq, PartialEq)]
#[derive(Debug, Clone, Builder, Eq, PartialEq)]
#[builder(build_fn(error = "ConfigBuildError"))]
#[builder(derive(Deserialize))]
#[serde(deny_unknown_fields)]
#[builder(derive(Debug, Serialize, Deserialize))]
pub struct PathConfig {
/// Set the length of a bit-prefix for a default IPv4 subnet-family.
///
/// Any two relays will be considered to belong to the same family if their
/// IPv4 addresses share at least this many initial bits.
#[builder(default = "ipv4_prefix_default()")]
#[serde(default = "ipv4_prefix_default")]
ipv4_subnet_family_prefix: u8,
/// Set the length of a bit-prefix for a default IPv6 subnet-family.
@ -40,7 +38,6 @@ pub struct PathConfig {
/// Any two relays will be considered to belong to the same family if their
/// IPv6 addresses share at least this many initial bits.
#[builder(default = "ipv6_prefix_default()")]
#[serde(default = "ipv6_prefix_default")]
ipv6_subnet_family_prefix: u8,
}
@ -94,16 +91,14 @@ impl Default for PathConfig {
/// use [`PreemptiveCircuitConfigBuilder`].
///
/// Except as noted, this configuration can be changed on a running Arti client.
#[derive(Debug, Clone, Builder, Deserialize, Eq, PartialEq)]
#[derive(Debug, Clone, Builder, Eq, PartialEq)]
#[builder(build_fn(error = "ConfigBuildError"))]
#[builder(derive(Deserialize))]
#[serde(deny_unknown_fields)]
#[builder(derive(Debug, Serialize, Deserialize))]
pub struct PreemptiveCircuitConfig {
/// If we have at least this many available circuits, we suspend
/// construction of preemptive circuits. whether our available circuits
/// support our predicted exit ports or not.
#[builder(default = "default_preemptive_threshold()")]
#[serde(default = "default_preemptive_threshold")]
pub(crate) disable_at_threshold: usize,
/// At startup, which exit ports should we expect that the client will want?
@ -122,14 +117,12 @@ pub struct PreemptiveCircuitConfig {
/// should we predict that the client will still want to have circuits
/// available for that port?
#[builder(default = "default_preemptive_duration()")]
#[serde(with = "humantime_serde", default = "default_preemptive_duration")]
#[builder_field_attr(serde(with = "humantime_serde::option"))]
pub(crate) prediction_lifetime: Duration,
/// How many available circuits should we try to have, at minimum, for each
/// predicted exit port?
#[builder(default = "default_preemptive_min_exit_circs_for_port()")]
#[serde(default = "default_preemptive_min_exit_circs_for_port")]
pub(crate) min_exit_circs_for_port: usize,
}
@ -143,15 +136,13 @@ pub struct PreemptiveCircuitConfig {
/// not currently expired, and the request timing of all _future_
/// requests. However, there are currently bugs: see bug
/// [#263](https://gitlab.torproject.org/tpo/core/arti/-/issues/263).
#[derive(Debug, Clone, Builder, Deserialize, Eq, PartialEq)]
#[derive(Debug, Clone, Builder, Eq, PartialEq)]
#[builder(build_fn(error = "ConfigBuildError"))]
#[builder(derive(Deserialize))]
#[serde(deny_unknown_fields)]
#[builder(derive(Debug, Serialize, Deserialize))]
pub struct CircuitTiming {
/// How long after a circuit has first been used should we give
/// it out for new requests?
#[builder(default = "default_max_dirtiness()")]
#[serde(with = "humantime_serde", default = "default_max_dirtiness")]
#[builder_field_attr(serde(with = "humantime_serde::option"))]
pub(crate) max_dirtiness: Duration,
@ -159,7 +150,6 @@ pub struct CircuitTiming {
/// after this much time.
// TODO: Impose a maximum or minimum?
#[builder(default = "default_request_timeout()")]
#[serde(with = "humantime_serde", default = "default_request_timeout")]
#[builder_field_attr(serde(with = "humantime_serde::option"))]
pub(crate) request_timeout: Duration,
@ -167,14 +157,12 @@ pub struct CircuitTiming {
/// this many attempts.
// TODO: Impose a maximum or minimum?
#[builder(default = "default_request_max_retries()")]
#[serde(default = "default_request_max_retries")]
pub(crate) request_max_retries: u32,
/// When waiting for requested circuits, wait at least this long
/// before using a suitable-looking circuit launched by some other
/// request.
#[builder(default = "default_request_loyalty()")]
#[serde(with = "humantime_serde", default = "default_request_loyalty")]
#[builder_field_attr(serde(with = "humantime_serde::option"))]
pub(crate) request_loyalty: Duration,
}

View File

@ -47,17 +47,17 @@
//!
//! ```
//! use derive_builder::Builder;
//! use serde::Deserialize;
//! use serde::{Deserialize, Serialize};
//! use tor_config::{define_list_builder_helper, define_list_builder_accessors, ConfigBuildError};
//!
//! #[derive(Builder, Debug, Eq, PartialEq)]
//! #[builder(build_fn(error = "ConfigBuildError"))]
//! #[builder(derive(Deserialize))]
//! #[builder(derive(Debug, Serialize, Deserialize))]
//! pub struct Thing { value: i32 }
//!
//! #[derive(Builder, Debug, Eq, PartialEq)]
//! #[builder(build_fn(error = "ConfigBuildError"))]
//! #[builder(derive(Deserialize))]
//! #[builder(derive(Debug, Serialize, Deserialize))]
//! pub struct Outer {
//! /// List of things, being built as part of the configuration
//! #[builder(sub_builder, setter(custom))]
@ -93,12 +93,12 @@
//!
//! ```
//! use derive_builder::Builder;
//! use serde::Deserialize;
//! use serde::{Deserialize, Serialize};
//! use tor_config::{define_list_builder_helper, define_list_builder_accessors, ConfigBuildError};
//!
//! #[derive(Builder, Debug, Eq, PartialEq)]
//! #[builder(build_fn(error = "ConfigBuildError"))]
//! #[builder(derive(Deserialize))]
//! #[builder(derive(Debug, Serialize, Deserialize))]
//! pub struct Outer {
//! /// List of values, being built as part of the configuration
//! #[builder(sub_builder, setter(custom))]
@ -148,7 +148,8 @@
/// for example if the list is to be included in a struct in another module or crate.
/// Usually `$field_vis` should be the same as `$vis`.
///
/// `#[derive(Default, Clone, Deserialize)]` will be applied to the generated builder,
/// `#[derive(Default, Clone, Debug, Serialize, Deserialize)]`
/// will be applied to the generated builder,
/// but you can specify other attributes too.
/// There is no need to supply any documentation; this is an internal struct and
/// the macro will supply a suitable (bland) doc comment.
@ -201,7 +202,8 @@ macro_rules! define_list_builder_helper {
default = $default:expr;
$( item_build: $item_build:expr; )?
} => {
#[derive($crate::educe::Educe, Clone, $crate::serde::Deserialize)]
#[derive($crate::educe::Educe, Clone, Debug)]
#[derive($crate::serde::Serialize, $crate::serde::Deserialize)]
#[educe(Default)]
#[serde(transparent)]
$(#[ $docs_and_attrs ])*
@ -340,14 +342,14 @@ define_list_builder_helper! {
///
/// ```
/// use derive_builder::Builder;
/// use serde::Deserialize;
/// use serde::{Deserialize, Serialize};
/// use tor_config::{ConfigBuildError};
/// use tor_config::{define_list_builder_accessors, list_builder::VecBuilder};
/// use std::net::SocketAddr;
///
/// #[derive(Debug, Clone, Builder)]
/// #[builder(build_fn(error = "ConfigBuildError"))]
/// #[builder(derive(Deserialize))]
/// #[builder(derive(Debug, Serialize, Deserialize))]
/// pub struct FallbackDir {
/// #[builder(sub_builder(fn_name = "build"), setter(custom))]
/// orports: Vec<SocketAddr>,
@ -375,11 +377,11 @@ define_list_builder_helper! {
#[cfg(test)]
mod test {
use derive_builder::Builder;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
#[test]
fn nonempty_default() {
#[derive(Eq, PartialEq, Builder, Deserialize)]
#[derive(Eq, PartialEq, Builder, Serialize, Deserialize)]
struct Outer {
#[builder(sub_builder, setter(custom))]
list: List,

View File

@ -4,7 +4,7 @@
//! consensus directory.
use derive_builder::Builder;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use tor_config::{define_list_builder_helper, ConfigBuildError};
use tor_llcrypto::pk::rsa::RsaIdentity;
@ -13,9 +13,9 @@ use tor_llcrypto::pk::rsa::RsaIdentity;
// Note that we do *not* set serde(deny_unknown_fields)] on this structure:
// we want our authorities format to be future-proof against adding new info
// about each authority.
#[derive(Deserialize, Debug, Clone, Builder, Eq, PartialEq)]
#[derive(Debug, Clone, Builder, Eq, PartialEq)]
#[builder(build_fn(error = "ConfigBuildError"))]
#[builder(derive(Deserialize))]
#[builder(derive(Debug, Serialize, Deserialize))]
pub struct Authority {
/// A memorable nickname for this authority.
#[builder(setter(into))]

View File

@ -18,7 +18,7 @@ use tor_guardmgr::fallback::FallbackListBuilder;
use tor_netdoc::doc::netstatus;
use derive_builder::Builder;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
/// Configuration information about the Tor network itself; used as
@ -29,10 +29,9 @@ use std::path::PathBuf;
//
// TODO: We should move this type around, since the fallbacks part will no longer be used in
// dirmgr, but only in guardmgr. Probably this type belongs in `arti-client`.
#[derive(Deserialize, Debug, Clone, Builder, Eq, PartialEq)]
#[serde(deny_unknown_fields)]
#[derive(Debug, Clone, Builder, Eq, PartialEq)]
#[builder(build_fn(validate = "Self::validate", error = "ConfigBuildError"))]
#[builder(derive(Deserialize))]
#[builder(derive(Debug, Serialize, Deserialize))]
pub struct NetworkConfig {
/// List of locations to look in when downloading directory information, if
/// we don't actually have a directory yet.
@ -45,7 +44,6 @@ pub struct NetworkConfig {
///
/// The default is to use a set of compiled-in fallback directories,
/// whose addresses and public keys are shipped as part of the Arti source code.
#[serde(default)]
#[builder(sub_builder, setter(custom))]
pub(crate) fallback_caches: tor_guardmgr::fallback::FallbackList,
@ -115,10 +113,9 @@ impl NetworkConfigBuilder {
///
/// This type is immutable once constructed. To make one, use
/// [`DownloadScheduleConfigBuilder`], or deserialize it from a string.
#[derive(Deserialize, Debug, Clone, Builder, Eq, PartialEq)]
#[serde(deny_unknown_fields)]
#[derive(Debug, Clone, Builder, Eq, PartialEq)]
#[builder(build_fn(error = "ConfigBuildError"))]
#[builder(derive(Deserialize))]
#[builder(derive(Debug, Serialize, Deserialize))]
pub struct DownloadScheduleConfig {
/// Top-level configuration for how to retry our initial bootstrap attempt.
#[builder(

View File

@ -7,16 +7,15 @@ use std::num::{NonZeroU32, NonZeroU8};
use std::time::Duration;
use derive_builder::Builder;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use tor_basic_utils::retry::RetryDelay;
use tor_config::ConfigBuildError;
/// Configuration for how many times to retry a download, with what
/// frequency.
#[derive(Debug, Builder, Copy, Clone, Deserialize, Eq, PartialEq)]
#[serde(deny_unknown_fields)]
#[derive(Debug, Builder, Copy, Clone, Eq, PartialEq)]
#[builder(build_fn(error = "ConfigBuildError"))]
#[builder(derive(Deserialize))]
#[builder(derive(Debug, Serialize, Deserialize))]
pub struct DownloadSchedule {
/// How many attempts to make before giving up?
#[builder(
@ -30,14 +29,12 @@ pub struct DownloadSchedule {
/// The amount of time to delay after the first failure, and a
/// lower-bound for future delays.
#[serde(with = "humantime_serde")]
#[builder(default = "Duration::from_millis(1000)")]
#[builder_field_attr(serde(with = "humantime_serde::option"))]
initial_delay: Duration,
/// When we want to download a bunch of these at a time, how many
/// attempts should we try to launch at once?
#[serde(default = "default_parallelism")]
#[builder(
setter(strip_option),
field(
@ -93,12 +90,6 @@ where
})
}
/// Return the default parallelism for DownloadSchedule.
fn default_parallelism() -> NonZeroU8 {
#![allow(clippy::unwrap_used)]
1.try_into().unwrap()
}
impl DownloadSchedule {
/// Return a new [`DownloadScheduleBuilder`]
pub fn builder() -> DownloadScheduleBuilder {

View File

@ -19,7 +19,7 @@ use tor_config::{define_list_builder_accessors, list_builder::VecBuilder};
use tor_llcrypto::pk::ed25519::Ed25519Identity;
use tor_llcrypto::pk::rsa::RsaIdentity;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
use crate::dirstatus::DirStatus;
@ -33,9 +33,9 @@ pub use set::{FallbackList, FallbackListBuilder};
// Note that we do *not* set serde(deny_unknown_fields) on this
// structure: we want our fallback directory configuration format to
// be future-proof against adding new info about each fallback.
#[derive(Debug, Clone, Deserialize, Builder, Eq, PartialEq)]
#[derive(Debug, Clone, Builder, Eq, PartialEq)]
#[builder(build_fn(private, name = "build_unvalidated", error = "ConfigBuildError"))]
#[builder(derive(Deserialize))]
#[builder(derive(Debug, Serialize, Deserialize))]
pub struct FallbackDir {
/// RSA identity for the directory relay
rsa_identity: RsaIdentity,

View File

@ -7,7 +7,6 @@ use std::time::{Duration, Instant};
use super::{DirStatus, FallbackDir, FallbackDirBuilder};
use crate::fallback::default_fallbacks;
use crate::{ids::FallbackId, PickGuardError};
use serde::Deserialize;
use tor_config::define_list_builder_helper;
/// A list of fallback directories.
@ -15,8 +14,7 @@ use tor_config::define_list_builder_helper;
/// Fallback directories (represented by [`FallbackDir`]) are used by Tor
/// clients when they don't already have enough other directory information to
/// contact the network.
#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize)]
#[serde(transparent)]
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct FallbackList {
/// The underlying fallbacks in this set.
fallbacks: Vec<FallbackDir>,

View File

@ -1265,7 +1265,7 @@ impl GuardUsageBuilder {
/// They're suitable for things like making sure that we don't start
/// and end a circuit at the same relay, or requiring a specific
/// subprotocol version for certain kinds of requests.
#[derive(Clone, Debug, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub enum GuardRestriction {
/// Don't pick a guard with the provided Ed25519 identity.