From 83c59b0a56e5453414fe81dfc74d5c687fb866fa Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:17:06 +0100 Subject: [PATCH 01/31] tor-netdoc: Un-gate features in types/policy.rs These are all parse2, and there are no blocking TODOs. --- crates/tor-netdoc/src/types/policy.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/tor-netdoc/src/types/policy.rs b/crates/tor-netdoc/src/types/policy.rs index 640656e335..7f58c89789 100644 --- a/crates/tor-netdoc/src/types/policy.rs +++ b/crates/tor-netdoc/src/types/policy.rs @@ -27,7 +27,6 @@ pub use addrpolicy::{AddrPolicy, AddrPortPattern}; pub use portpolicy::PortPolicy; use crate::NormalItemArgument; -#[cfg(feature = "parse2")] use crate::parse2::{ArgumentError, ArgumentStream, ItemArgumentParseable}; /// Error from an unparsable or invalid policy. @@ -306,7 +305,6 @@ impl FromStr for PortRanges { } } -#[cfg(feature = "parse2")] impl ItemArgumentParseable for PortRanges { /// [`PortRanges`] argument parser which is odd because port ranges are /// syntactically a single argument although semantically multiple ones. @@ -459,7 +457,7 @@ mod test { ] ); - #[cfg(feature = "parse2")] + // XXXX move this code out of the now-pointless block { use crate::parse2::{self, ParseInput}; -- GitLab From 3efab98c7973a54b2f24d0cd68b3f3f418f1f97b Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:18:56 +0100 Subject: [PATCH 02/31] tor-netdoc: Un-gate features in types/policy.rs (tidy) Remove a now-pointless pair of { }. We'll reindent this in a moment. --- crates/tor-netdoc/src/types/policy.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/crates/tor-netdoc/src/types/policy.rs b/crates/tor-netdoc/src/types/policy.rs index 7f58c89789..2fea011751 100644 --- a/crates/tor-netdoc/src/types/policy.rs +++ b/crates/tor-netdoc/src/types/policy.rs @@ -348,6 +348,8 @@ mod test { //! use super::*; use crate::Result; + use crate::parse2::{self, ParseInput}; + #[test] fn parse_portrange() -> Result<()> { assert_eq!( @@ -457,10 +459,6 @@ mod test { ] ); - // XXXX move this code out of the now-pointless block - { - use crate::parse2::{self, ParseInput}; - #[derive(derive_deftly::Deftly)] #[derive_deftly(NetdocParseable)] struct Dummy { @@ -471,6 +469,5 @@ mod test { parse2::parse_netdoc::(&ParseInput::new(&format!("dummy {INPUT}\n"), "")) .unwrap(); assert_eq!(ranges, ranges2.dummy); - } } } -- GitLab From 0025cb307d7ea1e6ff546ffe6698811a80b79237 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:19:29 +0100 Subject: [PATCH 03/31] tor-netdoc: Un-gate features in types/policy.rs (fmt) --- crates/tor-netdoc/src/types/policy.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/tor-netdoc/src/types/policy.rs b/crates/tor-netdoc/src/types/policy.rs index 2fea011751..9a6f3c2cdd 100644 --- a/crates/tor-netdoc/src/types/policy.rs +++ b/crates/tor-netdoc/src/types/policy.rs @@ -459,15 +459,15 @@ mod test { ] ); - #[derive(derive_deftly::Deftly)] - #[derive_deftly(NetdocParseable)] - struct Dummy { - #[deftly(netdoc(single_arg))] - dummy: PortRanges, - } - let ranges2 = - parse2::parse_netdoc::(&ParseInput::new(&format!("dummy {INPUT}\n"), "")) - .unwrap(); - assert_eq!(ranges, ranges2.dummy); + #[derive(derive_deftly::Deftly)] + #[derive_deftly(NetdocParseable)] + struct Dummy { + #[deftly(netdoc(single_arg))] + dummy: PortRanges, + } + let ranges2 = + parse2::parse_netdoc::(&ParseInput::new(&format!("dummy {INPUT}\n"), "")) + .unwrap(); + assert_eq!(ranges, ranges2.dummy); } } -- GitLab From 23faf4095bea3945a1bf1ec0e561aa683e585f3e Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:20:59 +0100 Subject: [PATCH 04/31] tor-netdoc: Un-gate features in types/policy/portpolicy.rs These are all parse2, and there are no blocking TODOs. --- crates/tor-netdoc/src/types/policy/portpolicy.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/crates/tor-netdoc/src/types/policy/portpolicy.rs b/crates/tor-netdoc/src/types/policy/portpolicy.rs index dae0df13b0..07bf586f38 100644 --- a/crates/tor-netdoc/src/types/policy/portpolicy.rs +++ b/crates/tor-netdoc/src/types/policy/portpolicy.rs @@ -6,13 +6,11 @@ use std::fmt::Display; use std::str::FromStr; use std::sync::Arc; -#[cfg(feature = "parse2")] use crate::parse2::{ErrorProblem as EP, ItemValueParseable, UnparsedItem}; use super::{PolicyError, PortRanges, RuleKind}; use tor_basic_utils::intern::InternCache; -#[cfg(feature = "parse2")] use derive_deftly::Deftly; /// A policy to match zero or more TCP/UDP ports. @@ -126,7 +124,6 @@ impl FromStr for PortPolicy { } } -#[cfg(feature = "parse2")] impl ItemValueParseable for PortPolicy { // Manual implementation incorporating the `accept`/`reject`, // using `.invert()` if necessary to yield simply a `PortPolicy`, @@ -183,13 +180,9 @@ mod test { #![allow(clippy::needless_pass_by_value)] //! use itertools::Itertools; - - #[cfg(feature = "parse2")] use crate::parse2::{self, ParseInput}; - use super::*; - #[cfg(feature = "parse2")] #[derive(derive_deftly::Deftly)] #[derive_deftly(NetdocParseable)] struct Dummy { @@ -207,7 +200,7 @@ mod test { for p in deny { assert!(!policy.allows_port(*p)); } - #[cfg(feature = "parse2")] + // XXXX remove { } { let policy2 = parse2::parse_netdoc::(&ParseInput::new(&format!("dummy {inp}"), "")) @@ -268,7 +261,7 @@ mod test { "reject 5,4,3,2", ] { assert!(s.parse::().is_err()); - #[cfg(feature = "parse2")] + // XXXX remove { } { assert!( parse2::parse_netdoc::(&ParseInput::new(&format!("dummy {s}"), "")) -- GitLab From 1cb560b7c8c789b6c85affe6f40942ac848532a8 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:21:54 +0100 Subject: [PATCH 05/31] tor-netdoc: Un-gate features in types/policy/portpolicy.rs (tidy) --- crates/tor-netdoc/src/types/policy/portpolicy.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/crates/tor-netdoc/src/types/policy/portpolicy.rs b/crates/tor-netdoc/src/types/policy/portpolicy.rs index 07bf586f38..b3ca49b3f6 100644 --- a/crates/tor-netdoc/src/types/policy/portpolicy.rs +++ b/crates/tor-netdoc/src/types/policy/portpolicy.rs @@ -200,8 +200,6 @@ mod test { for p in deny { assert!(!policy.allows_port(*p)); } - // XXXX remove { } - { let policy2 = parse2::parse_netdoc::(&ParseInput::new(&format!("dummy {inp}"), "")) .unwrap() @@ -212,7 +210,6 @@ mod test { for p in deny { assert!(!policy2.allows_port(*p)); } - } } check( @@ -261,13 +258,10 @@ mod test { "reject 5,4,3,2", ] { assert!(s.parse::().is_err()); - // XXXX remove { } - { assert!( parse2::parse_netdoc::(&ParseInput::new(&format!("dummy {s}"), "")) .is_err() ); - } } } -- GitLab From ddab69d0aafec41ceafb176176dfe0bc4c48cdfc Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:22:33 +0100 Subject: [PATCH 06/31] tor-netdoc: Un-gate features in types/policy/portpolicy.rs (fmt) --- .../tor-netdoc/src/types/policy/portpolicy.rs | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/crates/tor-netdoc/src/types/policy/portpolicy.rs b/crates/tor-netdoc/src/types/policy/portpolicy.rs index b3ca49b3f6..7ca46aafa2 100644 --- a/crates/tor-netdoc/src/types/policy/portpolicy.rs +++ b/crates/tor-netdoc/src/types/policy/portpolicy.rs @@ -179,9 +179,9 @@ mod test { #![allow(clippy::useless_vec)] #![allow(clippy::needless_pass_by_value)] //! - use itertools::Itertools; - use crate::parse2::{self, ParseInput}; use super::*; + use crate::parse2::{self, ParseInput}; + use itertools::Itertools; #[derive(derive_deftly::Deftly)] #[derive_deftly(NetdocParseable)] @@ -200,16 +200,16 @@ mod test { for p in deny { assert!(!policy.allows_port(*p)); } - let policy2 = - parse2::parse_netdoc::(&ParseInput::new(&format!("dummy {inp}"), "")) - .unwrap() - .dummy; - for p in allow { - assert!(policy2.allows_port(*p)); - } - for p in deny { - assert!(!policy2.allows_port(*p)); - } + let policy2 = + parse2::parse_netdoc::(&ParseInput::new(&format!("dummy {inp}"), "")) + .unwrap() + .dummy; + for p in allow { + assert!(policy2.allows_port(*p)); + } + for p in deny { + assert!(!policy2.allows_port(*p)); + } } check( @@ -258,10 +258,9 @@ mod test { "reject 5,4,3,2", ] { assert!(s.parse::().is_err()); - assert!( - parse2::parse_netdoc::(&ParseInput::new(&format!("dummy {s}"), "")) - .is_err() - ); + assert!( + parse2::parse_netdoc::(&ParseInput::new(&format!("dummy {s}"), "")).is_err() + ); } } -- GitLab From e88dd607e412ac9ceef19b5f4c8b3f1c0f3f44dc Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:24:03 +0100 Subject: [PATCH 07/31] tor-netdoc: Un-gate features in types/family.rs There is one TODO DIRMIRROR but it's a possible API change. I think it doesn't mean we can't un-gate this now. --- crates/tor-netdoc/src/types/family.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/tor-netdoc/src/types/family.rs b/crates/tor-netdoc/src/types/family.rs index ecaf594cc8..eddab82062 100644 --- a/crates/tor-netdoc/src/types/family.rs +++ b/crates/tor-netdoc/src/types/family.rs @@ -26,7 +26,7 @@ use tor_llcrypto::pk::rsa::RsaIdentity; /// /// TODO: This type probably belongs in a different crate. #[derive(Clone, Debug, Default, Hash, Eq, PartialEq, Deftly)] -#[cfg_attr(feature = "parse2", derive_deftly(ItemValueParseable))] +#[derive_deftly(ItemValueParseable)] pub struct RelayFamily(Vec); /// Cache of RelayFamily objects, for saving memory. @@ -152,7 +152,7 @@ impl NormalItemArgument for RelayFamilyId {} /// A list of multiple [`RelayFamilyId`] entries as found in microdescs. #[derive(Clone, Debug, Default, Eq, PartialEq, Deftly, derive_more::AsRef)] -#[cfg_attr(feature = "parse2", derive_deftly(ItemValueParseable))] +#[derive_deftly(ItemValueParseable)] pub struct RelayFamilyIds( // TODO DIRMIRROR: Replace with BTreeSet at one point. // TODO could/should this be a type alias instead? @@ -274,10 +274,9 @@ mod test { } #[test] - #[cfg(feature = "parse2")] fn parse2() { #[derive(Debug, PartialEq, Eq, derive_deftly::Deftly)] - #[cfg_attr(feature = "parse2", derive_deftly(NetdocParseable))] + #[derive_deftly(NetdocParseable)] struct Wrapper { family: RelayFamily, } -- GitLab From 84f47100ac5fa94aa9f75c1c8c40e836c9e96c1e Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:26:06 +0100 Subject: [PATCH 08/31] tor-netdoc: Un-gate features in types/policy/addrpolicy.rs There is only one TODO in this file and it's not really relevant. --- crates/tor-netdoc/src/types/policy/addrpolicy.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/crates/tor-netdoc/src/types/policy/addrpolicy.rs b/crates/tor-netdoc/src/types/policy/addrpolicy.rs index 41aba7cc2e..3950cb6c8d 100644 --- a/crates/tor-netdoc/src/types/policy/addrpolicy.rs +++ b/crates/tor-netdoc/src/types/policy/addrpolicy.rs @@ -6,7 +6,6 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; use std::str::FromStr; use crate::NormalItemArgument; -#[cfg(feature = "parse2")] use crate::parse2::{ ErrorProblem as EP, ItemArgumentParseable, KeywordRef, NetdocParseableFields, UnparsedItem, }; @@ -84,7 +83,6 @@ impl AddrPolicy { } } -#[cfg(feature = "parse2")] impl NetdocParseableFields for AddrPolicy { type Accumulator = AddrPolicy; @@ -450,7 +448,6 @@ mod test { assert_eq!(&x2, &x); } - #[cfg(feature = "parse2")] #[test] fn parse2() { use crate::{ -- GitLab From 1381f865ef4c4ac8b5d9b7c41d3cca4bf24a1d59 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:27:55 +0100 Subject: [PATCH 09/31] tor-netdoc: Un-gate parse2 and encode in types/relay_flags.rs There is one irrelevant TODO. --- crates/tor-netdoc/src/types/relay_flags.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/crates/tor-netdoc/src/types/relay_flags.rs b/crates/tor-netdoc/src/types/relay_flags.rs index dd4d0ceb89..4209d4cf09 100644 --- a/crates/tor-netdoc/src/types/relay_flags.rs +++ b/crates/tor-netdoc/src/types/relay_flags.rs @@ -267,21 +267,16 @@ mod parse_impl { } /// New parser impl -#[cfg(any(feature = "parse2", feature = "encode"))] mod parse2_impl { use super::*; - #[cfg(feature = "parse2")] use crate::parse2::{self, ErrorProblem as EP}; - - #[cfg(feature = "encode")] use { crate::encode::ItemEncoder, itertools::chain, std::collections::BTreeSet, tor_error::Bug, }; impl<'s, M: ReprMode> ParserEncoder<'s, M> { /// Parse relay flags - #[cfg(feature = "parse2")] #[allow(clippy::needless_pass_by_value)] // we must match trait signature pub(crate) fn from_unparsed(item: parse2::UnparsedItem<'_>) -> Result { item.check_no_object()?; @@ -295,7 +290,6 @@ mod parse2_impl { } /// Encode relay flags - #[cfg(feature = "encode")] #[allow(clippy::unnecessary_wraps)] // we must match trait signature #[allow(clippy::redundant_closure)] // rust-clippy/issues#14215 |f| <&'static str>::from(f) pub(crate) fn write_item_value_onto( -- GitLab From 189727c24e5be3a4967172f6715029edfe70da1f Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:29:18 +0100 Subject: [PATCH 10/31] tor-netdoc: Un-gate parse2 in doc/routerdesc.rs This is just one cfg, for RelayPlatform. --- crates/tor-netdoc/src/doc/routerdesc.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/tor-netdoc/src/doc/routerdesc.rs b/crates/tor-netdoc/src/doc/routerdesc.rs index 2d6aa4d920..4fd467c29e 100644 --- a/crates/tor-netdoc/src/doc/routerdesc.rs +++ b/crates/tor-netdoc/src/doc/routerdesc.rs @@ -214,7 +214,6 @@ impl std::str::FromStr for RelayPlatform { } } -#[cfg(feature = "parse2")] impl ItemArgumentParseable for RelayPlatform { fn from_args<'s>(args: &mut ArgumentStream<'s>) -> std::result::Result { args.into_remaining() -- GitLab From 1b975f122741ee1f86a1d405d36f699e034a2c1a Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:14:49 +0100 Subject: [PATCH 11/31] tor-netdoc: Un-gate features in doc/microdesc.rs These are all parse2, and there are no blocking TODOs. We're leaving `build_docs` alone. --- crates/tor-netdoc/src/doc/microdesc.rs | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/crates/tor-netdoc/src/doc/microdesc.rs b/crates/tor-netdoc/src/doc/microdesc.rs index 3f4db94ad7..cadbd0789e 100644 --- a/crates/tor-netdoc/src/doc/microdesc.rs +++ b/crates/tor-netdoc/src/doc/microdesc.rs @@ -33,7 +33,6 @@ use std::sync::Arc; use std::sync::LazyLock; use std::time; -#[cfg(feature = "parse2")] use crate::parse2::ItemObjectParseable; #[cfg(feature = "build_docs")] @@ -62,7 +61,7 @@ pub type MdDigest = [u8; DOC_DIGEST_LEN]; /// /// #[derive(Clone, Debug, Deftly, PartialEq, Eq)] -#[cfg_attr(feature = "parse2", derive_deftly(NetdocParseable))] +#[derive_deftly(NetdocParseable)] #[non_exhaustive] pub struct Microdesc { /// The legacy onion key, whose object is optional but whose item serves @@ -74,31 +73,28 @@ pub struct Microdesc { onion_key: OnionKeyIntro, /// Public key used for the ntor circuit extension protocol. - #[cfg_attr(feature = "parse2", deftly(netdoc(single_arg)))] + #[deftly(netdoc(single_arg))] pub ntor_onion_key: Curve25519Public, /// Declared family for this relay. - #[cfg_attr(feature = "parse2", deftly(netdoc(default)))] + #[deftly(netdoc(default))] pub family: Arc, /// Family identities for this relay. - #[cfg_attr(feature = "parse2", deftly(netdoc(default)))] + #[deftly(netdoc(default))] pub family_ids: RelayFamilyIds, /// List of IPv4 ports to which this relay will exit - #[cfg_attr(feature = "parse2", deftly(netdoc(keyword = "p", default)))] + #[deftly(netdoc(keyword = "p", default))] pub ipv4_policy: Arc, /// List of IPv6 ports to which this relay will exit - #[cfg_attr(feature = "parse2", deftly(netdoc(keyword = "p6", default)))] + #[deftly(netdoc(keyword = "p6", default))] pub ipv6_policy: Arc, /// Ed25519 identity for this relay // TODO SPEC: Set this to "exactly once". - #[cfg_attr( - feature = "parse2", - deftly(netdoc(keyword = "id", with = "Ed25519IdentityLine")) - )] + #[deftly(netdoc(keyword = "id", with = "Ed25519IdentityLine"))] pub ed25519_id: Ed25519IdentityLine, // addr is obsolete and doesn't go here any more @@ -108,7 +104,7 @@ pub struct Microdesc { /// it, and when listing it in a consensus document. // TODO: maybe this belongs somewhere else. Once it's used to store // correlate the microdesc to a consensus, it's never used again. - #[cfg_attr(feature = "parse2", deftly(netdoc(skip)))] + #[deftly(netdoc(skip))] pub sha256: MdDigest, } @@ -165,9 +161,9 @@ impl Microdesc { /// The object (the onion key) is deprecated and optional, but the item itself /// must be present, because it is used to mark the start of the netdoc. #[derive(Debug, Clone, Default, Deftly, PartialEq, Eq)] -#[cfg_attr(feature = "parse2", derive_deftly(ItemValueParseable))] +#[derive_deftly(ItemValueParseable)] struct OnionKeyIntro( - #[cfg_attr(feature = "parse2", deftly(netdoc(object)))] Option, + #[deftly(netdoc(object))] Option, ); /// A microdescriptor annotated with additional data @@ -663,7 +659,6 @@ mod test { /// replaced by a copy and paste in the case one replaces the testdata2 /// vector's in the future. #[test] - #[cfg(feature = "parse2")] fn parse2() { use tor_llcrypto::pk::ed25519::Ed25519Identity; @@ -716,7 +711,6 @@ Yl0wCKpUZFHs5CHsajLSfXZKHkwfqRXFEJu9aMtmQdQFfqE9JOJHAgMBAAE= // TODO: This should be included in testdata2/ but that would require the // chutney/shadow integration test to actually do families at all. #[test] - #[cfg(feature = "parse2")] fn parse2_happy_family() { use tor_llcrypto::pk::ed25519::Ed25519Identity; -- GitLab From b3869d22a4b3ce24cee903c7953ccbd91df0f2b1 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:24:55 +0100 Subject: [PATCH 12/31] tor-netdoc: Un-gate features in doc/microdesc.rs (fmt) --- crates/tor-netdoc/src/doc/microdesc.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/tor-netdoc/src/doc/microdesc.rs b/crates/tor-netdoc/src/doc/microdesc.rs index cadbd0789e..740ebde00a 100644 --- a/crates/tor-netdoc/src/doc/microdesc.rs +++ b/crates/tor-netdoc/src/doc/microdesc.rs @@ -162,9 +162,7 @@ impl Microdesc { /// must be present, because it is used to mark the start of the netdoc. #[derive(Debug, Clone, Default, Deftly, PartialEq, Eq)] #[derive_deftly(ItemValueParseable)] -struct OnionKeyIntro( - #[deftly(netdoc(object))] Option, -); +struct OnionKeyIntro(#[deftly(netdoc(object))] Option); /// A microdescriptor annotated with additional data /// -- GitLab From 1b68c979fba0136faebf1b1a83a5a909b6b2b10a Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:40:25 +0100 Subject: [PATCH 13/31] tor-netdoc: Upgrade a TODO re NetworkStatusUnverifiedVote --- crates/tor-netdoc/src/doc/netstatus.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/tor-netdoc/src/doc/netstatus.rs b/crates/tor-netdoc/src/doc/netstatus.rs index 5981bbce90..3d29287d4a 100644 --- a/crates/tor-netdoc/src/doc/netstatus.rs +++ b/crates/tor-netdoc/src/doc/netstatus.rs @@ -1771,7 +1771,7 @@ mod test { let file = "testdata2/v3-status-votes--1"; let text = fs::read_to_string(file)?; - // TODO replace the poc struct here when we have parsing of proper whole votes + // TODO DIRAUTH replace the poc struct here when we have parsing of proper whole votes use crate::parse2::poc::netstatus::NetworkStatusUnverifiedVote; let input = ParseInput::new(&text, file); -- GitLab From b0b7925668f3b725f157b65c29a39129098a3c09 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:36:25 +0100 Subject: [PATCH 14/31] tor-netdoc: Un-gate parse2 and encode mods in doc/netstatus.rs This stabilises the parse2 and encode impls of * NetParams * ProtoStatuses It also stabilises the parse2 impls of the following types which do not currently have any encode impls: * RelayWeight * rs::SoftwareVersion * IgnoredPublicationTimeSp As for TODOs and incomplete code: the things we're stabilising here are very simple, or fully formed. Implementing encoding for IgnoredPublicationTimeSp looks impossible, but we can cross that bridge when we come to it. We un-cfg-gate the parse2 and encode imports too. --- crates/tor-netdoc/src/doc/netstatus.rs | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/crates/tor-netdoc/src/doc/netstatus.rs b/crates/tor-netdoc/src/doc/netstatus.rs index 3d29287d4a..5414215824 100644 --- a/crates/tor-netdoc/src/doc/netstatus.rs +++ b/crates/tor-netdoc/src/doc/netstatus.rs @@ -60,17 +60,15 @@ pub mod vote; #[cfg(feature = "build_docs")] mod build; -#[cfg(feature = "encode")] +// XXXX unify and tidy use { crate::encode::{ItemValueEncodable, NetdocEncodable, NetdocEncoder}, // tor_error::Bug, }; -#[cfg(feature = "parse2")] use { crate::parse2::{self, ArgumentStream, ItemValueParseable}, // }; -#[cfg(feature = "parse2")] pub use { parse2::{ErrorProblem, IsStructural, ItemStream, KeywordRef, NetdocParseable, StopAt}, proto_statuses_parse2_encode::ProtoStatusesNetdocParseAccumulator, // @@ -1279,8 +1277,7 @@ impl RelayWeight { /// `parse2` impls for types in this modulea /// -/// Separate module to save on repeated `cfg` and for a separate namespace. -#[cfg(feature = "parse2")] +/// Separate module for a separate namespace. mod parse2_impls { use super::*; pub(super) use parse2::{ @@ -1332,8 +1329,7 @@ mod parse2_impls { /// `encode` impls for types in this modulea /// -/// Separate module to save on repeated `cfg` and for a separate namespace. -#[cfg(feature = "encode")] +/// Separate module for a separate namespace. mod encode_impls { use super::*; use std::result::Result; @@ -1379,12 +1375,9 @@ impl Footer { /// `ProtoStatuses` parsing and encoding /// -/// Separate module to save on repeated `cfg` to hide the helper struct -#[cfg(any(feature = "encode", feature = "parse2"))] +/// Separate module for separate namespace mod proto_statuses_parse2_encode { - #[cfg(feature = "encode")] use super::encode_impls::*; - #[cfg(feature = "parse2")] use super::parse2_impls::*; use super::*; use paste::paste; @@ -1406,7 +1399,6 @@ mod proto_statuses_parse2_encode { macro_rules! impl_proto_statuses { { $( $rr:ident $cr:ident; )* } => { paste! { #[derive(Deftly)] #[derive_deftly(NetdocParseableFields)] - #[cfg(feature = "parse2")] // Only ProtoStatusesParseNetdocParseAccumulator is exposed. #[allow(unreachable_pub)] pub struct ProtoStatusesParseHelper { @@ -1417,11 +1409,9 @@ mod proto_statuses_parse2_encode { } /// Partially parsed `ProtoStatuses` - #[cfg(feature = "parse2")] pub use ProtoStatusesParseHelperNetdocParseAccumulator as ProtoStatusesNetdocParseAccumulator; - #[cfg(feature = "parse2")] impl NetdocParseableFields for ProtoStatuses { type Accumulator = ProtoStatusesNetdocParseAccumulator; fn is_item_keyword(kw: KeywordRef<'_>) -> bool { @@ -1443,7 +1433,6 @@ mod proto_statuses_parse2_encode { } } - #[cfg(feature = "encode")] impl NetdocEncodableFields for ProtoStatuses { fn encode_fields(&self, out: &mut NetdocEncoder) -> Result<(), Bug> { $( @@ -1884,7 +1873,7 @@ mod test { let p = "Hello=Goodbye Fred=7".parse::>(); assert!(p.is_err()); - #[cfg(feature = "encode")] + // XXXX remove { } { use crate::encode::{ItemValueEncodable, NetdocEncoder}; -- GitLab From 0c4655775035ce0d63b8740a346df1119f4cada4 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 13:08:32 +0100 Subject: [PATCH 15/31] tor-netdoc: Un-gate parse2 and encode mods in doc/netstatus.rs (tidy) Tidy the imports, and remove some now-unneeded { }. We'll run rustfmt in a moment to sort and reindent. --- crates/tor-netdoc/src/doc/netstatus.rs | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/crates/tor-netdoc/src/doc/netstatus.rs b/crates/tor-netdoc/src/doc/netstatus.rs index 5414215824..5bd1b7d32e 100644 --- a/crates/tor-netdoc/src/doc/netstatus.rs +++ b/crates/tor-netdoc/src/doc/netstatus.rs @@ -60,27 +60,20 @@ pub mod vote; #[cfg(feature = "build_docs")] mod build; -// XXXX unify and tidy -use { - crate::encode::{ItemValueEncodable, NetdocEncodable, NetdocEncoder}, // - tor_error::Bug, -}; -use { - crate::parse2::{self, ArgumentStream, ItemValueParseable}, // -}; - -pub use { - parse2::{ErrorProblem, IsStructural, ItemStream, KeywordRef, NetdocParseable, StopAt}, - proto_statuses_parse2_encode::ProtoStatusesNetdocParseAccumulator, // -}; +pub use proto_statuses_parse2_encode::ProtoStatusesNetdocParseAccumulator; #[cfg(all(feature = "parse2", feature = "plain-consensus"))] use crate::doc::authcert::EncodedAuthCert; use crate::doc::authcert::{AuthCert, AuthCertKeyIds}; +use crate::encode::{ItemValueEncodable, NetdocEncodable, NetdocEncoder}; use crate::parse::keyword::Keyword; use crate::parse::parser::{Section, SectionRules, SectionRulesBuilder}; use crate::parse::tokenize::{Item, ItemResult, NetDocReader}; +use crate::parse2::{ + self, ArgumentStream, ItemValueParseable, + ErrorProblem, IsStructural, ItemStream, KeywordRef, NetdocParseable, StopAt, +}; use crate::types::misc::*; use crate::types::relay_flags::{self, DocRelayFlags}; use crate::util::PeekableIterator; @@ -91,7 +84,7 @@ use std::result::Result as StdResult; use std::str::FromStr; use std::sync::Arc; use std::{net, result, time}; -use tor_error::{HasKind, bad_api_usage, internal}; +use tor_error::{Bug, HasKind, bad_api_usage, internal}; use tor_protover::Protocols; use derive_deftly::{Deftly, define_derive_deftly}; @@ -1873,10 +1866,6 @@ mod test { let p = "Hello=Goodbye Fred=7".parse::>(); assert!(p.is_err()); - // XXXX remove { } - { - use crate::encode::{ItemValueEncodable, NetdocEncoder}; - for bad_kw in ["What=The", "", "\n", "\0"] { let p = [(bad_kw, 42)].into_iter().collect::>(); let mut d = NetdocEncoder::new(); @@ -1887,7 +1876,6 @@ mod test { })(); let _: tor_error::Bug = d.expect_err(bad_kw); } - } } #[test] -- GitLab From 61d27093b10bcc24db0a9147ac666da2bb5ef706 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:50:38 +0100 Subject: [PATCH 16/31] tor-netdoc: Un-gate parse2 and encode mods in doc/netstatus.rs (fmt) --- crates/tor-netdoc/src/doc/netstatus.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/tor-netdoc/src/doc/netstatus.rs b/crates/tor-netdoc/src/doc/netstatus.rs index 5bd1b7d32e..470715df69 100644 --- a/crates/tor-netdoc/src/doc/netstatus.rs +++ b/crates/tor-netdoc/src/doc/netstatus.rs @@ -71,8 +71,8 @@ use crate::parse::keyword::Keyword; use crate::parse::parser::{Section, SectionRules, SectionRulesBuilder}; use crate::parse::tokenize::{Item, ItemResult, NetDocReader}; use crate::parse2::{ - self, ArgumentStream, ItemValueParseable, - ErrorProblem, IsStructural, ItemStream, KeywordRef, NetdocParseable, StopAt, + self, ArgumentStream, ErrorProblem, IsStructural, ItemStream, ItemValueParseable, KeywordRef, + NetdocParseable, StopAt, }; use crate::types::misc::*; use crate::types::relay_flags::{self, DocRelayFlags}; @@ -1866,16 +1866,16 @@ mod test { let p = "Hello=Goodbye Fred=7".parse::>(); assert!(p.is_err()); - for bad_kw in ["What=The", "", "\n", "\0"] { - let p = [(bad_kw, 42)].into_iter().collect::>(); - let mut d = NetdocEncoder::new(); - let d = (|| { - let i = d.item("bad-psrams"); - p.write_item_value_onto(i)?; - d.finish() - })(); - let _: tor_error::Bug = d.expect_err(bad_kw); - } + for bad_kw in ["What=The", "", "\n", "\0"] { + let p = [(bad_kw, 42)].into_iter().collect::>(); + let mut d = NetdocEncoder::new(); + let d = (|| { + let i = d.item("bad-psrams"); + p.write_item_value_onto(i)?; + d.finish() + })(); + let _: tor_error::Bug = d.expect_err(bad_kw); + } } #[test] -- GitLab From a2bf074c4756660f202abeb2d55aa62be76b2e31 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:51:46 +0100 Subject: [PATCH 17/31] tor-netdoc: Un-gate features impls in doc/netstatus/dir_source.rs There are no outstanding TODOs here. --- crates/tor-netdoc/src/doc/netstatus/dir_source.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/crates/tor-netdoc/src/doc/netstatus/dir_source.rs b/crates/tor-netdoc/src/doc/netstatus/dir_source.rs index 5687fe90f8..5e02f6f315 100644 --- a/crates/tor-netdoc/src/doc/netstatus/dir_source.rs +++ b/crates/tor-netdoc/src/doc/netstatus/dir_source.rs @@ -48,7 +48,7 @@ define_derive_deftly! { // /// #[derive(Debug, Clone, Deftly, amplify::Getters)] - #[cfg_attr(feature = "encode", derive_deftly(ItemValueEncodable))] + #[derive_deftly(ItemValueEncodable)] #[derive_deftly_adhoc] // ignore deftly attrs directed at Constructor pub struct SupersededAuthorityKey { /// Real nickname for this authority, not including the `-legacy` @@ -96,7 +96,6 @@ define_derive_deftly! { /// Instead we derive `ItemValueParseable` on this and convert it ad-hoc /// in `ConsensusAuthoritySection`'s parser. #[derive(Debug, Clone, Deftly)] - #[cfg(feature = "parse2")] #[derive_deftly(ItemValueParseable)] #[derive_deftly_adhoc] // ignore deftly attrs directed at Constructor struct RawDirSource { @@ -106,7 +105,6 @@ define_derive_deftly! { $DEFINE_NORMAL_FIELDS } - #[cfg(feature = "parse2")] impl RawDirSource { /// Convert into the public representation. fn into_superseded(self) -> Result { @@ -134,9 +132,9 @@ define_derive_deftly! { /// #[derive(Debug, Clone, Deftly)] #[derive_deftly(SupersededAuthorityKey)] -#[cfg_attr(feature = "parse2", derive_deftly(ItemValueParseable))] -#[cfg_attr(feature = "encode", derive_deftly(ItemValueEncodable))] -#[cfg_attr(not(any(feature = "parse2", feature = "encode")), derive_deftly_adhoc)] +// XXXX rewrap +#[derive_deftly(ItemValueParseable)] +#[derive_deftly(ItemValueEncodable)] #[derive_deftly(Constructor)] #[allow(clippy::exhaustive_structs)] pub struct DirSource { @@ -198,7 +196,6 @@ pub struct ConsensusAuthoritySection { pub __non_exhaustive: (), } -#[cfg(feature = "encode")] impl NetdocEncodable for ConsensusAuthoritySection { fn encode_unsigned(&self, out: &mut NetdocEncoder) -> Result<(), Bug> { // bind all fields so that if any are added we remember to encode them @@ -222,7 +219,6 @@ impl NetdocEncodable for ConsensusAuthoritySection { } } -#[cfg(feature = "parse2")] impl NetdocParseable for ConsensusAuthoritySection { fn doctype_for_error() -> &'static str { "consensus.authorities" -- GitLab From df08d15fdc8cfaf4e7ca0c0d0358ffef82583556 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:59:17 +0100 Subject: [PATCH 18/31] tor-netdoc: Un-gate features impls in doc/netstatus/dir_source.rs (rewrap) --- crates/tor-netdoc/src/doc/netstatus/dir_source.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/tor-netdoc/src/doc/netstatus/dir_source.rs b/crates/tor-netdoc/src/doc/netstatus/dir_source.rs index 5e02f6f315..bda0b8b009 100644 --- a/crates/tor-netdoc/src/doc/netstatus/dir_source.rs +++ b/crates/tor-netdoc/src/doc/netstatus/dir_source.rs @@ -131,11 +131,8 @@ define_derive_deftly! { /// Corresponds to a dir-source line which is *not* a "superseded authority key entry". /// #[derive(Debug, Clone, Deftly)] +#[derive_deftly(Constructor, ItemValueParseable, ItemValueEncodable)] #[derive_deftly(SupersededAuthorityKey)] -// XXXX rewrap -#[derive_deftly(ItemValueParseable)] -#[derive_deftly(ItemValueEncodable)] -#[derive_deftly(Constructor)] #[allow(clippy::exhaustive_structs)] pub struct DirSource { /// human-readable nickname for this authority. -- GitLab From 94d89fe742b0dded448249e59b75e6fd09b0870f Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 13:03:39 +0100 Subject: [PATCH 19/31] tor-netdoc: Un-gate parse2 and encode loose impls in doc/netstatus.rs This stabilises the parse2 and encode impls of * Lifetime * ConsensusMethods * SharedRandStatus * ConsensusAuthorityEntry All of these are complete. --- crates/tor-netdoc/src/doc/netstatus.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/tor-netdoc/src/doc/netstatus.rs b/crates/tor-netdoc/src/doc/netstatus.rs index 470715df69..cda70fa95d 100644 --- a/crates/tor-netdoc/src/doc/netstatus.rs +++ b/crates/tor-netdoc/src/doc/netstatus.rs @@ -154,10 +154,9 @@ pub struct IgnoredPublicationTimeSp; #[derive(Clone, Debug, Deftly)] #[derive_deftly(Constructor)] #[derive_deftly(Lifetime)] -#[cfg_attr(feature = "encode", derive_deftly(NetdocEncodableFields))] -#[cfg_attr(feature = "parse2", derive_deftly(NetdocParseableFields))] -// derive_deftly_adhoc disables unused deftly attribute checking, so we needn't cfg_attr them all -#[cfg_attr(not(any(feature = "parse2", feature = "encode")), derive_deftly_adhoc)] +// XXXX rewrap +#[derive_deftly(NetdocEncodableFields)] +#[derive_deftly(NetdocParseableFields)] #[allow(clippy::exhaustive_structs)] pub struct Lifetime { /// `valid-after` --- Time at which the document becomes valid @@ -269,8 +268,9 @@ impl NormalItemArgument for ConsensusMethod {} /// /// There is also [`consensus_methods_comma_separated`] for `m` lines in votes. #[derive(Debug, Clone, Default, Eq, PartialEq, Deftly)] -#[cfg_attr(feature = "parse2", derive_deftly(ItemValueParseable))] -#[cfg_attr(feature = "encode", derive_deftly(ItemValueEncodable))] +// XXXX rewrap +#[derive_deftly(ItemValueParseable)] +#[derive_deftly(ItemValueEncodable)] #[non_exhaustive] pub struct ConsensusMethods { /// Consensus methods. @@ -281,7 +281,6 @@ pub struct ConsensusMethods { /// /// As found in an `m` item in a vote: /// -#[cfg(feature = "parse2")] pub mod consensus_methods_comma_separated { use super::*; use parse2::ArgumentError as AE; @@ -569,8 +568,9 @@ pub struct SharedRandVal([u8; 32]); /// along with meta-information about that value. #[derive(Debug, Clone, Deftly)] #[non_exhaustive] -#[cfg_attr(feature = "parse2", derive_deftly(ItemValueParseable))] -#[cfg_attr(feature = "encode", derive_deftly(ItemValueEncodable))] +// XXXX rewrap +#[derive_deftly(ItemValueParseable)] +#[derive_deftly(ItemValueEncodable)] pub struct SharedRandStatus { /// How many authorities revealed shares that contributed to this value. pub n_reveals: u8, @@ -628,9 +628,9 @@ pub type MdAuthorityEntry = ConsensusAuthorityEntry; // 1. That avoids separating the two consensus authority entry types, which are identical // 2. The only common fields are `dir-source` and `contact`, so there is little duplication #[derive(Debug, Clone, Deftly)] -#[cfg_attr(feature = "parse2", derive_deftly(NetdocParseable))] -#[cfg_attr(feature = "encode", derive_deftly(NetdocEncodable))] -#[cfg_attr(not(any(feature = "parse2", feature = "encode")), derive_deftly_adhoc)] +// XXXX rewrap +#[derive_deftly(NetdocParseable)] +#[derive_deftly(NetdocEncodable)] #[derive_deftly(Constructor)] #[allow(clippy::exhaustive_structs)] pub struct ConsensusAuthorityEntry { -- GitLab From fcc5975a6cebde38870862df27931c1ea919f4ec Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 13:11:46 +0100 Subject: [PATCH 20/31] tor-netdoc: Un-gate parse2 and encode loose impls in doc/netstatus.rs (rewrap) --- crates/tor-netdoc/src/doc/netstatus.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/crates/tor-netdoc/src/doc/netstatus.rs b/crates/tor-netdoc/src/doc/netstatus.rs index cda70fa95d..420f8f5df2 100644 --- a/crates/tor-netdoc/src/doc/netstatus.rs +++ b/crates/tor-netdoc/src/doc/netstatus.rs @@ -152,11 +152,8 @@ pub struct IgnoredPublicationTimeSp; /// /// Aggregate of three netdoc preamble fields. #[derive(Clone, Debug, Deftly)] -#[derive_deftly(Constructor)] +#[derive_deftly(Constructor, NetdocEncodableFields, NetdocParseableFields)] #[derive_deftly(Lifetime)] -// XXXX rewrap -#[derive_deftly(NetdocEncodableFields)] -#[derive_deftly(NetdocParseableFields)] #[allow(clippy::exhaustive_structs)] pub struct Lifetime { /// `valid-after` --- Time at which the document becomes valid @@ -268,9 +265,7 @@ impl NormalItemArgument for ConsensusMethod {} /// /// There is also [`consensus_methods_comma_separated`] for `m` lines in votes. #[derive(Debug, Clone, Default, Eq, PartialEq, Deftly)] -// XXXX rewrap -#[derive_deftly(ItemValueParseable)] -#[derive_deftly(ItemValueEncodable)] +#[derive_deftly(ItemValueEncodable, ItemValueParseable)] #[non_exhaustive] pub struct ConsensusMethods { /// Consensus methods. @@ -568,9 +563,7 @@ pub struct SharedRandVal([u8; 32]); /// along with meta-information about that value. #[derive(Debug, Clone, Deftly)] #[non_exhaustive] -// XXXX rewrap -#[derive_deftly(ItemValueParseable)] -#[derive_deftly(ItemValueEncodable)] +#[derive_deftly(ItemValueEncodable, ItemValueParseable)] pub struct SharedRandStatus { /// How many authorities revealed shares that contributed to this value. pub n_reveals: u8, @@ -628,10 +621,7 @@ pub type MdAuthorityEntry = ConsensusAuthorityEntry; // 1. That avoids separating the two consensus authority entry types, which are identical // 2. The only common fields are `dir-source` and `contact`, so there is little duplication #[derive(Debug, Clone, Deftly)] -// XXXX rewrap -#[derive_deftly(NetdocParseable)] -#[derive_deftly(NetdocEncodable)] -#[derive_deftly(Constructor)] +#[derive_deftly(Constructor, NetdocEncodable, NetdocParseable)] #[allow(clippy::exhaustive_structs)] pub struct ConsensusAuthorityEntry { /// Contents of the `dir-source` line about an authority -- GitLab From 0ebdf22e9c9285a3a4069bbe1b7e0566be4d49d4 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 13:58:23 +0100 Subject: [PATCH 21/31] tor-netdoc: Un-gate parse2 and encode loose impls under doc/netstatus This stabilises the parse2 and encode impls of consensus tyepe: * {plain, md}::{Preamble, RouterStatus, RouterStatusIntroItem} It also un-gates the parse2 and encode impls of some vote types. * VoteAuthorityEntry - this type has been completed. * RouterStatusMdDigestsVote - whole type still gated with ns-vote Re the remaining vote types (vote::*): although each_variety.rs doesn't have a cfg itself, there is a feature gate in the variety macrology. --- crates/tor-netdoc/src/doc/netstatus.rs | 6 ++--- .../src/doc/netstatus/each_variety.rs | 7 +++-- crates/tor-netdoc/src/doc/netstatus/rs.rs | 9 +++---- .../src/doc/netstatus/rs/each_variety.rs | 27 +++++++++---------- crates/tor-netdoc/src/doc/netstatus/rs/md.rs | 1 - 5 files changed, 21 insertions(+), 29 deletions(-) diff --git a/crates/tor-netdoc/src/doc/netstatus.rs b/crates/tor-netdoc/src/doc/netstatus.rs index 420f8f5df2..44c9e9d667 100644 --- a/crates/tor-netdoc/src/doc/netstatus.rs +++ b/crates/tor-netdoc/src/doc/netstatus.rs @@ -660,9 +660,9 @@ pub struct ConsensusAuthorityEntry { /// TODO DIRAUTH not all fields are here yet. // They have individual comments, below. #[derive(Debug, Clone, Deftly)] -#[cfg_attr(feature = "parse2", derive_deftly(NetdocParseable))] -#[cfg_attr(feature = "encode", derive_deftly(NetdocEncodable))] -#[cfg_attr(not(any(feature = "parse2", feature = "encode")), derive_deftly_adhoc)] +// XXXX rewrap +#[derive_deftly(NetdocParseable)] +#[derive_deftly(NetdocEncodable)] #[derive_deftly(Constructor)] #[allow(clippy::exhaustive_structs)] pub struct VoteAuthorityEntry { diff --git a/crates/tor-netdoc/src/doc/netstatus/each_variety.rs b/crates/tor-netdoc/src/doc/netstatus/each_variety.rs index 513f199d1a..e110a6b77a 100644 --- a/crates/tor-netdoc/src/doc/netstatus/each_variety.rs +++ b/crates/tor-netdoc/src/doc/netstatus/each_variety.rs @@ -30,11 +30,10 @@ ns_use_this_variety! { // and is missing some consensus fields that need to be manipulated by dirauths; // there are individual TODO comments about each such defect. #[derive(Clone, Debug, Deftly)] +// XXXX rewrap #[derive_deftly(Constructor)] -#[cfg_attr(feature = "parse2", derive_deftly(NetdocParseableFields))] -#[cfg_attr(feature = "encode", derive_deftly(NetdocEncodableFields))] -// derive_deftly_adhoc disables unused deftly attribute checking, so we needn't cfg_attr them all -#[cfg_attr(not(any(feature = "parse2", feature = "encode")), derive_deftly_adhoc)] +#[derive_deftly(NetdocParseableFields)] +#[derive_deftly(NetdocEncodableFields)] #[allow(clippy::exhaustive_structs)] pub struct Preamble { /// Consensus methods supported by this voter. diff --git a/crates/tor-netdoc/src/doc/netstatus/rs.rs b/crates/tor-netdoc/src/doc/netstatus/rs.rs index 918833121f..377b5b0fa7 100644 --- a/crates/tor-netdoc/src/doc/netstatus/rs.rs +++ b/crates/tor-netdoc/src/doc/netstatus/rs.rs @@ -26,7 +26,7 @@ use tor_basic_utils::intern::InternCache; use tor_error::internal; use tor_llcrypto::pk::rsa::RsaIdentity; -#[cfg(feature = "parse2")] +// XXXX tidy use { super::consensus_methods_comma_separated, // derive_deftly::Deftly, @@ -69,14 +69,11 @@ static OTHER_VERSION_CACHE: InternCache = InternCache::new(); /// and across multiple instances of it within a `RouterStatus`. #[derive(Debug, Clone, Default, Eq, PartialEq)] #[cfg(feature = "ns-vote")] -#[cfg_attr(feature = "parse2", derive(Deftly), derive_deftly(ItemValueParseable))] +#[derive(Deftly)] #[derive_deftly(ItemValueParseable)] // XXXX tidy #[non_exhaustive] pub struct RouterStatusMdDigestsVote { /// The methods for which this document is applicable. - #[cfg_attr( - feature = "parse2", - deftly(netdoc(with = consensus_methods_comma_separated)) - )] + #[deftly(netdoc(with = consensus_methods_comma_separated))] pub consensus_methods: ConsensusMethods, /// The various hashes of this document. diff --git a/crates/tor-netdoc/src/doc/netstatus/rs/each_variety.rs b/crates/tor-netdoc/src/doc/netstatus/rs/each_variety.rs index 00d698fd72..40f209efa6 100644 --- a/crates/tor-netdoc/src/doc/netstatus/rs/each_variety.rs +++ b/crates/tor-netdoc/src/doc/netstatus/rs/each_variety.rs @@ -28,7 +28,6 @@ use super::*; // but they're just byte arrays and such impls would imply that byte arrays are always // represented the same way in netdocs which is very far from being true. // TODO consider introducing newtypes for routerdesc and microdesc hashes? -#[cfg(feature = "parse2")] ns_choose! { ( use doc_digest_parse2_real as doc_digest_parse2_r; // implemented here in rs/each_variety.rs use Ignored as doc_digest_parse2_m; @@ -49,7 +48,7 @@ ns_choose! { ( /// /// /// `r` item. -#[cfg_attr(feature = "parse2", derive(Deftly), derive_deftly(ItemValueParseable))] +#[derive(Deftly)] #[derive_deftly(ItemValueParseable)] // XXXX tidy #[derive(Debug, Clone)] #[non_exhaustive] pub struct RouterStatusIntroItem { @@ -63,7 +62,7 @@ pub struct RouterStatusIntroItem { /// Digest of the document for this relay (except md consensuses) // TODO SPEC rename in the spec from `digest` to "doc_digest" // TODO SPEC in md consensuses the referenced document digest is in a separate `m` item - #[cfg_attr(feature = "parse2", deftly(netdoc(with = doc_digest_parse2_r)))] + #[deftly(netdoc(with = doc_digest_parse2_r))] pub doc_digest: ns_type!(DocDigest, NotPresent, DocDigest), /// Publication time. pub publication: ns_type!( @@ -87,7 +86,7 @@ pub struct RouterStatusIntroItem { // In most netdocs we would use the item keywords as the field names. But routerstatus // entry keywords are chosen to be very short to minimise the consensus size, so we // use longer names in the struct and specify the keyword separately. -#[cfg_attr(feature = "parse2", derive(Deftly), derive_deftly(NetdocParseable))] +#[derive(Deftly)] #[derive_deftly(NetdocParseable)] // XXXX tidy #[derive(Debug, Clone)] #[non_exhaustive] pub struct RouterStatus { @@ -106,42 +105,41 @@ pub struct RouterStatus { /// `r` item. // We call this field `m` rather than `doc_digest` because it's not always the doc digest. // TODO SPEC in all but md consensuses the referenced document digest is in the `r` intro item - #[cfg_attr(feature = "parse2", deftly(netdoc(with = doc_digest_parse2_m)))] + #[deftly(netdoc(with = doc_digest_parse2_m))] pub m: ns_type!(NotPresent, DocDigest, Vec), /// `a` --- Further router address(es) (IPv6) /// /// /// (and, the md version, which is different). - #[cfg_attr(feature = "parse2", deftly(netdoc(single_arg)))] + #[deftly(netdoc(single_arg))] pub a: Vec, /// `s` --- Router status flags /// /// - #[cfg_attr( - feature = "parse2", - deftly(netdoc(keyword = "s")), - deftly(netdoc(with = { relay_flags::ParserEncoder:: })) - )] + #[deftly(netdoc( + keyword = "s", + with = { relay_flags::ParserEncoder:: }, + ))] pub flags: DocRelayFlags, /// `v` --- Relay's Tor software version /// /// - #[cfg_attr(feature = "parse2", deftly(netdoc(keyword = "v")))] + #[deftly(netdoc(keyword = "v"))] pub version: Option, /// `pr` --- Subprotocol capabilities supported /// /// - #[cfg_attr(feature = "parse2", deftly(netdoc(keyword = "pr")))] + #[deftly(netdoc(keyword = "pr"))] pub protos: Protocols, /// `w` --- Bandwidth estimates /// /// - #[cfg_attr(feature = "parse2", deftly(netdoc(keyword = "w")))] + #[deftly(netdoc(keyword = "w"))] pub weight: RelayWeight, } @@ -161,7 +159,6 @@ impl RouterStatus { /// /// This field is present in `r` items, except for md consensuses, where it's in `m`. /// Hence the `_real`, which lets us swap it out for each variety. -#[cfg(feature = "parse2")] pub(crate) mod doc_digest_parse2_real { use super::*; use crate::parse2::ArgumentError as AE; diff --git a/crates/tor-netdoc/src/doc/netstatus/rs/md.rs b/crates/tor-netdoc/src/doc/netstatus/rs/md.rs index a4083ea94f..22216dbf48 100644 --- a/crates/tor-netdoc/src/doc/netstatus/rs/md.rs +++ b/crates/tor-netdoc/src/doc/netstatus/rs/md.rs @@ -28,7 +28,6 @@ impl RouterStatus { /// See `doc_digest_parse2_real` in `rs/each_variety.rs`. /// This is in `md.rs` because it's needed only for md consensuses. /// Elsewhere, the value is in the `r` item, so is merely `ItemArgumentParseable`. -#[cfg(feature = "parse2")] pub(crate) mod doc_digest_parse2_real_item { use super::*; use crate::parse2::ErrorProblem as EP; -- GitLab From 9ab32243acbc19ca19eb04bd5aa326aed00bf15b Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 14:20:25 +0100 Subject: [PATCH 22/31] tor-netdoc: Un-gate parse2 and encode loose impls under doc/netstatus (tidy) --- crates/tor-netdoc/src/doc/netstatus.rs | 5 +---- crates/tor-netdoc/src/doc/netstatus/each_variety.rs | 5 +---- crates/tor-netdoc/src/doc/netstatus/rs.rs | 13 ++++--------- .../tor-netdoc/src/doc/netstatus/rs/each_variety.rs | 8 ++++---- 4 files changed, 10 insertions(+), 21 deletions(-) diff --git a/crates/tor-netdoc/src/doc/netstatus.rs b/crates/tor-netdoc/src/doc/netstatus.rs index 44c9e9d667..307f9a54c2 100644 --- a/crates/tor-netdoc/src/doc/netstatus.rs +++ b/crates/tor-netdoc/src/doc/netstatus.rs @@ -660,10 +660,7 @@ pub struct ConsensusAuthorityEntry { /// TODO DIRAUTH not all fields are here yet. // They have individual comments, below. #[derive(Debug, Clone, Deftly)] -// XXXX rewrap -#[derive_deftly(NetdocParseable)] -#[derive_deftly(NetdocEncodable)] -#[derive_deftly(Constructor)] +#[derive_deftly(Constructor, NetdocEncodable, NetdocParseable)] #[allow(clippy::exhaustive_structs)] pub struct VoteAuthorityEntry { /// Contents of the `dir-source` line about an authority diff --git a/crates/tor-netdoc/src/doc/netstatus/each_variety.rs b/crates/tor-netdoc/src/doc/netstatus/each_variety.rs index e110a6b77a..9648b2dbde 100644 --- a/crates/tor-netdoc/src/doc/netstatus/each_variety.rs +++ b/crates/tor-netdoc/src/doc/netstatus/each_variety.rs @@ -30,10 +30,7 @@ ns_use_this_variety! { // and is missing some consensus fields that need to be manipulated by dirauths; // there are individual TODO comments about each such defect. #[derive(Clone, Debug, Deftly)] -// XXXX rewrap -#[derive_deftly(Constructor)] -#[derive_deftly(NetdocParseableFields)] -#[derive_deftly(NetdocEncodableFields)] +#[derive_deftly(Constructor, NetdocEncodableFields, NetdocParseableFields)] #[allow(clippy::exhaustive_structs)] pub struct Preamble { /// Consensus methods supported by this voter. diff --git a/crates/tor-netdoc/src/doc/netstatus/rs.rs b/crates/tor-netdoc/src/doc/netstatus/rs.rs index 377b5b0fa7..565a90ca6f 100644 --- a/crates/tor-netdoc/src/doc/netstatus/rs.rs +++ b/crates/tor-netdoc/src/doc/netstatus/rs.rs @@ -11,7 +11,7 @@ pub(crate) mod plain; #[cfg(feature = "ns-vote")] pub(crate) mod vote; -use super::{ConsensusFlavor, ConsensusMethods}; +use super::{ConsensusFlavor, ConsensusMethods, consensus_methods_comma_separated}; use crate::doc::netstatus::NetstatusKwd; use crate::doc::netstatus::{IgnoredPublicationTimeSp, Protocols, RelayWeight}; use crate::parse::parser::Section; @@ -19,6 +19,7 @@ use crate::types::misc::*; use crate::types::relay_flags::{self, DocRelayFlags, RelayFlag, RelayFlags}; use crate::types::version::TorVersion; use crate::{Error, NetdocErrorKind as EK, Result}; +use derive_deftly::Deftly; use itertools::chain; use std::sync::Arc; use std::{net, time}; @@ -26,12 +27,6 @@ use tor_basic_utils::intern::InternCache; use tor_error::internal; use tor_llcrypto::pk::rsa::RsaIdentity; -// XXXX tidy -use { - super::consensus_methods_comma_separated, // - derive_deftly::Deftly, -}; - /// A version as presented in a router status. /// /// This can either be a parsed Tor version, or an unparsed string. @@ -67,9 +62,9 @@ static OTHER_VERSION_CACHE: InternCache = InternCache::new(); /// must sort it. /// * These non-invariants apply both within one instance of this struct, /// and across multiple instances of it within a `RouterStatus`. -#[derive(Debug, Clone, Default, Eq, PartialEq)] +#[derive(Debug, Clone, Default, Eq, PartialEq, Deftly)] #[cfg(feature = "ns-vote")] -#[derive(Deftly)] #[derive_deftly(ItemValueParseable)] // XXXX tidy +#[derive_deftly(ItemValueParseable)] #[non_exhaustive] pub struct RouterStatusMdDigestsVote { /// The methods for which this document is applicable. diff --git a/crates/tor-netdoc/src/doc/netstatus/rs/each_variety.rs b/crates/tor-netdoc/src/doc/netstatus/rs/each_variety.rs index 40f209efa6..596ee71ae3 100644 --- a/crates/tor-netdoc/src/doc/netstatus/rs/each_variety.rs +++ b/crates/tor-netdoc/src/doc/netstatus/rs/each_variety.rs @@ -48,8 +48,8 @@ ns_choose! { ( /// /// /// `r` item. -#[derive(Deftly)] #[derive_deftly(ItemValueParseable)] // XXXX tidy -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Deftly)] +#[derive_deftly(ItemValueParseable)] #[non_exhaustive] pub struct RouterStatusIntroItem { /// The nickname for this relay. @@ -86,8 +86,8 @@ pub struct RouterStatusIntroItem { // In most netdocs we would use the item keywords as the field names. But routerstatus // entry keywords are chosen to be very short to minimise the consensus size, so we // use longer names in the struct and specify the keyword separately. -#[derive(Deftly)] #[derive_deftly(NetdocParseable)] // XXXX tidy -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Deftly)] +#[derive_deftly(NetdocParseable)] #[non_exhaustive] pub struct RouterStatus { /// `r` --- Introduce a routerstatus entry -- GitLab From 8372f693f32ded32f82d0a9aaebe06d6ecf74bb1 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 12:54:50 +0100 Subject: [PATCH 23/31] tor-netdoc: Un-gate top-level NetdocBuilder This is only used for hsdescs right now. But it doesn't need to be gated behind encode. --- crates/tor-netdoc/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/tor-netdoc/src/lib.rs b/crates/tor-netdoc/src/lib.rs index f3bd31758d..075aba4596 100644 --- a/crates/tor-netdoc/src/lib.rs +++ b/crates/tor-netdoc/src/lib.rs @@ -76,8 +76,6 @@ pub use util::batching_split_before; pub use err::{BuildError, Error, NetdocErrorKind, Pos}; -#[cfg(feature = "encode")] -#[cfg_attr(docsrs, doc(cfg(feature = "encode")))] pub use encode::NetdocBuilder; /// Alias for the Result type returned by most objects in this module. -- GitLab From 562b2d7bd0779725994b318ff5b31e08b78f7c10 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 14:28:52 +0100 Subject: [PATCH 24/31] tor-netdoc: Un-gate "routerdesc" cargo feature As per #2492. --- crates/tor-netdoc/README.md | 6 +++--- crates/tor-netdoc/src/doc.rs | 12 ------------ crates/tor-netdoc/src/parse/tokenize.rs | 2 -- crates/tor-netdoc/src/types/embedded_cert.rs | 2 +- crates/tor-netdoc/src/types/misc.rs | 5 ----- 5 files changed, 4 insertions(+), 23 deletions(-) diff --git a/crates/tor-netdoc/README.md b/crates/tor-netdoc/README.md index 6955b516ca..1a3a07b87d 100644 --- a/crates/tor-netdoc/README.md +++ b/crates/tor-netdoc/README.md @@ -68,9 +68,6 @@ the parsers for the documents themselves. ## Features -`routerdesc`: enable support for the "router descriptor" document type, which -is needed by bridge clients and relays. - `plain-consensus`: enable support for the "plain (unflavoured) consensus" document type, which some relays cache and serve. @@ -90,6 +87,9 @@ not be used. Use of such features is (even more) at your own risk. #### Deprecated features +`routerdesc`: previously needed to enable support for the "router +descriptor" document type. This support is now enabled unconditionally. + `build_docs`: enable code to construct the objects representing different network documents, with builder patterns. diff --git a/crates/tor-netdoc/src/doc.rs b/crates/tor-netdoc/src/doc.rs index cc53fd2fd1..6e252c2887 100644 --- a/crates/tor-netdoc/src/doc.rs +++ b/crates/tor-netdoc/src/doc.rs @@ -38,16 +38,4 @@ pub mod hsdesc; pub mod microdesc; pub mod netstatus; -#[cfg(any(doc, feature = "routerdesc"))] pub mod routerdesc; - -// TODO: Do not define this twice but do `pub use` instead. -#[allow(missing_docs, clippy::missing_docs_in_private_items)] -#[cfg(not(any(doc, feature = "routerdesc")))] -pub mod routerdesc { - /// The digest of a RouterDesc document, as reported in a NS consensus. - pub type RdDigest = [u8; 20]; - - /// The digest of an ExtraInfo document, as reported in a RouterDesc. - pub type ExtraInfoDigest = [u8; 20]; -} diff --git a/crates/tor-netdoc/src/parse/tokenize.rs b/crates/tor-netdoc/src/parse/tokenize.rs index 85bfb2ab36..f683d2550d 100644 --- a/crates/tor-netdoc/src/parse/tokenize.rs +++ b/crates/tor-netdoc/src/parse/tokenize.rs @@ -513,7 +513,6 @@ impl<'a, 'b, K: Keyword> MaybeItem<'a, 'b, K> { /// If this item is present, parse its argument at position `idx`. /// Treat the absence or malformedness of the argument as an error, /// but treat the absence of this item as acceptable. - #[cfg(any(test, feature = "routerdesc"))] pub(crate) fn parse_arg(&self, idx: usize) -> Result> where Error: From, @@ -669,7 +668,6 @@ impl<'a, K: Keyword> NetDocReader<'a, K> { /// /// Like [`should_be_exhausted`](Self::should_be_exhausted), /// but permit empty lines at the end of the document. - #[cfg(feature = "routerdesc")] pub(crate) fn should_be_exhausted_but_for_empty_lines(&mut self) -> Result<()> { use crate::err::NetdocErrorKind as K; while let Some(Err(e)) = self.peek() { diff --git a/crates/tor-netdoc/src/types/embedded_cert.rs b/crates/tor-netdoc/src/types/embedded_cert.rs index 86866374eb..1d4f3b958f 100644 --- a/crates/tor-netdoc/src/types/embedded_cert.rs +++ b/crates/tor-netdoc/src/types/embedded_cert.rs @@ -237,5 +237,5 @@ where } } -#[cfg(all(test, feature = "routerdesc"))] +#[cfg(test)] mod test; diff --git a/crates/tor-netdoc/src/types/misc.rs b/crates/tor-netdoc/src/types/misc.rs index edd4c2d1ff..3a3e8859fe 100644 --- a/crates/tor-netdoc/src/types/misc.rs +++ b/crates/tor-netdoc/src/types/misc.rs @@ -10,7 +10,6 @@ pub use b64impl::*; pub use contact_info::*; pub use curve25519impl::*; pub use ed25519impl::*; -#[cfg(any(feature = "routerdesc", feature = "hs-common"))] pub(crate) use edcert::*; pub use fingerprint::*; pub use hostname::*; @@ -1143,11 +1142,9 @@ mod rsa { } /// Types for decoding Ed25519 certificates -#[cfg(any(feature = "routerdesc", feature = "hs-common"))] mod edcert { use crate::{NetdocErrorKind as EK, Pos, Result}; use tor_cert::{CertType, Ed25519Cert, KeyUnknownCert}; - #[cfg(feature = "routerdesc")] use tor_llcrypto::pk::ed25519; /// An ed25519 certificate as parsed from a directory object, with @@ -1183,7 +1180,6 @@ mod edcert { Ok(self) } /// Give an error if this certificate's subject_key is not `pk` - #[cfg(feature = "routerdesc")] pub(crate) fn check_subject_key_is(self, pk: &ed25519::Ed25519Identity) -> Result { if self.0.peek_subject_key().as_ed25519() != Some(pk) { return Err(EK::BadObjectVal @@ -2271,7 +2267,6 @@ mod test { assert!(failure.is_err()); } - #[cfg(feature = "routerdesc")] #[test] fn ed_cert() { use tor_llcrypto::pk::ed25519::Ed25519Identity; -- GitLab From 36d175b2728385c46067e421934f9262d0b8057e Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 14:08:29 +0100 Subject: [PATCH 25/31] tor-netdoc: Un-gate "plain-consensus" cargo feature As per #2492. --- crates/tor-netdoc/README.md | 7 ++++--- crates/tor-netdoc/src/doc/authcert.rs | 8 ++++---- crates/tor-netdoc/src/doc/netstatus.rs | 19 ++++--------------- crates/tor-netdoc/src/doc/netstatus/build.rs | 1 - crates/tor-netdoc/src/doc/netstatus/rs.rs | 1 - .../tor-netdoc/src/doc/netstatus/rs/build.rs | 1 - .../src/doc/ns_variety_definition_macros.rs | 4 ---- crates/tor-netdoc/src/parse2.rs | 2 +- 8 files changed, 13 insertions(+), 30 deletions(-) diff --git a/crates/tor-netdoc/README.md b/crates/tor-netdoc/README.md index 1a3a07b87d..a24ce0e01e 100644 --- a/crates/tor-netdoc/README.md +++ b/crates/tor-netdoc/README.md @@ -68,9 +68,6 @@ the parsers for the documents themselves. ## Features -`plain-consensus`: enable support for the "plain (unflavoured) consensus" document type, which -some relays cache and serve. - `hs-client`: enable support for parsing hidden service descriptors. `hs-service`: enable support for generating hidden service descriptors. @@ -90,6 +87,10 @@ not be used. Use of such features is (even more) at your own risk. `routerdesc`: previously needed to enable support for the "router descriptor" document type. This support is now enabled unconditionally. +`plain-consensus`: previously needed to enable support for the "plain +(unflavoured) consensus" document type. This support is now enabled +unconditionally. + `build_docs`: enable code to construct the objects representing different network documents, with builder patterns. diff --git a/crates/tor-netdoc/src/doc/authcert.rs b/crates/tor-netdoc/src/doc/authcert.rs index 581146ec51..2ac66ee20a 100644 --- a/crates/tor-netdoc/src/doc/authcert.rs +++ b/crates/tor-netdoc/src/doc/authcert.rs @@ -39,9 +39,9 @@ mod build; #[allow(deprecated)] pub use build::AuthCertBuilder; -#[cfg(all(feature = "plain-consensus", feature = "incomplete"))] +#[cfg(feature = "incomplete")] mod encoded; -#[cfg(all(feature = "plain-consensus", feature = "incomplete"))] +#[cfg(feature = "incomplete")] pub use encoded::EncodedAuthCert; decl_keyword! { @@ -677,7 +677,7 @@ impl AuthCert { /// as an [`EncodedAuthCert`]. // TODO these features are quite tangled // `EncodedAuthCert` is only available with `parse2` and `plain-consensus` - #[cfg(all(feature = "plain-consensus", feature = "incomplete"))] + #[cfg(feature = "incomplete")] pub fn encode_sign(&self, k_auth_id_rsa: &rsa::KeyPair) -> StdResult { let mut encoder = NetdocEncoder::new(); self.encode_unsigned(&mut encoder)?; @@ -1190,7 +1190,7 @@ mzMT023bleZ574az+117yNAr6XbIgqQfzbySzVLPXM8ZN9BrGR40KDZ2638ZJjRu } } - #[cfg(all(feature = "plain-consensus", feature = "incomplete"))] + #[cfg(feature = "incomplete")] mod encode_test { use super::*; use crate::parse2::{ParseInput, parse_netdoc}; diff --git a/crates/tor-netdoc/src/doc/netstatus.rs b/crates/tor-netdoc/src/doc/netstatus.rs index 307f9a54c2..17eedebcfc 100644 --- a/crates/tor-netdoc/src/doc/netstatus.rs +++ b/crates/tor-netdoc/src/doc/netstatus.rs @@ -52,7 +52,6 @@ mod dir_source; mod rs; pub mod md; -#[cfg(feature = "plain-consensus")] pub mod plain; #[cfg(feature = "ns-vote")] pub mod vote; @@ -62,7 +61,7 @@ mod build; pub use proto_statuses_parse2_encode::ProtoStatusesNetdocParseAccumulator; -#[cfg(all(feature = "parse2", feature = "plain-consensus"))] +#[cfg(feature = "incomplete")] use crate::doc::authcert::EncodedAuthCert; use crate::doc::authcert::{AuthCert, AuthCertKeyIds}; @@ -98,7 +97,7 @@ use serde::{Deserialize, Deserializer}; #[cfg(feature = "build_docs")] pub use build::MdConsensusBuilder; -#[cfg(all(feature = "build_docs", feature = "plain-consensus"))] +#[cfg(feature = "build_docs")] pub use build::PlainConsensusBuilder; #[cfg(feature = "build_docs")] ns_export_each_flavor! { @@ -110,16 +109,12 @@ ns_export_each_variety! { } #[deprecated] -#[cfg(feature = "ns_consensus")] pub use PlainConsensus as NsConsensus; #[deprecated] -#[cfg(feature = "ns_consensus")] pub use PlainRouterStatus as NsRouterStatus; #[deprecated] -#[cfg(feature = "ns_consensus")] pub use UncheckedPlainConsensus as UncheckedNsConsensus; #[deprecated] -#[cfg(feature = "ns_consensus")] pub use UnvalidatedPlainConsensus as UnvalidatedNsConsensus; #[cfg(feature = "ns-vote")] @@ -757,7 +752,7 @@ define_derive_deftly! { #[derive(Deftly, Clone, Debug)] #[derive_deftly(VoteAuthoritySection, Constructor)] #[allow(clippy::exhaustive_structs)] -#[cfg(all(feature = "parse2", feature = "plain-consensus"))] +#[cfg(feature = "parse2")] pub struct VoteAuthoritySection { /// Authority entry #[deftly(constructor)] @@ -796,17 +791,14 @@ pub type UnvalidatedMdConsensus = md::UnvalidatedConsensus; /// and timeliness. pub type UncheckedMdConsensus = md::UncheckedConsensus; -#[cfg(feature = "plain-consensus")] /// A consensus document that lists relays along with their /// router descriptor documents. pub type PlainConsensus = plain::Consensus; -#[cfg(feature = "plain-consensus")] /// An PlainConsensus that has been parsed and checked for timeliness, /// but not for signatures. pub type UnvalidatedPlainConsensus = plain::UnvalidatedConsensus; -#[cfg(feature = "plain-consensus")] /// An PlainConsensus that has been parsed but not checked for signatures /// and timeliness. pub type UncheckedPlainConsensus = plain::UncheckedConsensus; @@ -1626,9 +1618,7 @@ mod test { const CERTS: &str = include_str!("../../testdata/authcerts2.txt"); const CONSENSUS: &str = include_str!("../../testdata/mdconsensus1.txt"); - #[cfg(feature = "plain-consensus")] const PLAIN_CERTS: &str = include_str!("../../testdata2/cached-certs"); - #[cfg(feature = "plain-consensus")] const PLAIN_CONSENSUS: &str = include_str!("../../testdata2/cached-consensus"); fn read_bad(fname: &str) -> String { @@ -1709,7 +1699,6 @@ mod test { } #[test] - #[cfg(feature = "plain-consensus")] fn parse_and_validate_ns() -> Result<()> { use tor_checkable::{SelfSigned, Timebound}; let mut certs = Vec::new(); @@ -1735,7 +1724,7 @@ mod test { } #[test] - #[cfg(all(feature = "plain-consensus", feature = "incomplete"))] + #[cfg(feature = "incomplete")] fn parse2_vote() -> anyhow::Result<()> { let file = "testdata2/v3-status-votes--1"; let text = fs::read_to_string(file)?; diff --git a/crates/tor-netdoc/src/doc/netstatus/build.rs b/crates/tor-netdoc/src/doc/netstatus/build.rs index eb4a9907b5..39b5cb3a08 100644 --- a/crates/tor-netdoc/src/doc/netstatus/build.rs +++ b/crates/tor-netdoc/src/doc/netstatus/build.rs @@ -19,7 +19,6 @@ use std::sync::Arc; use std::time::SystemTime; pub(crate) mod md; -#[cfg(feature = "plain-consensus")] pub(crate) mod plain; ns_export_each_flavor! { diff --git a/crates/tor-netdoc/src/doc/netstatus/rs.rs b/crates/tor-netdoc/src/doc/netstatus/rs.rs index 565a90ca6f..c46627f8bd 100644 --- a/crates/tor-netdoc/src/doc/netstatus/rs.rs +++ b/crates/tor-netdoc/src/doc/netstatus/rs.rs @@ -6,7 +6,6 @@ #[cfg(feature = "build_docs")] pub(crate) mod build; pub(crate) mod md; -#[cfg(feature = "plain-consensus")] pub(crate) mod plain; #[cfg(feature = "ns-vote")] pub(crate) mod vote; diff --git a/crates/tor-netdoc/src/doc/netstatus/rs/build.rs b/crates/tor-netdoc/src/doc/netstatus/rs/build.rs index bd2999857b..ba50a4c4f5 100644 --- a/crates/tor-netdoc/src/doc/netstatus/rs/build.rs +++ b/crates/tor-netdoc/src/doc/netstatus/rs/build.rs @@ -10,5 +10,4 @@ use tor_protover::Protocols; use std::net::SocketAddr; pub(crate) mod md; -#[cfg(feature = "plain-consensus")] pub(crate) mod plain; diff --git a/crates/tor-netdoc/src/doc/ns_variety_definition_macros.rs b/crates/tor-netdoc/src/doc/ns_variety_definition_macros.rs index de50dd40ed..adc4ac319a 100644 --- a/crates/tor-netdoc/src/doc/ns_variety_definition_macros.rs +++ b/crates/tor-netdoc/src/doc/ns_variety_definition_macros.rs @@ -339,8 +339,6 @@ macro_rules! ns_export_each_variety { { @ [ $($case:tt)* ] [$($infix:tt)*] $id:ident } => { paste::paste!{ - #[cfg(feature = "plain-consensus")] - #[cfg_attr(docsrs, doc(cfg(feature = "plain-consensus")))] pub use { plain ::$id as [] }; // unconditional pub use { md ::$id as [] }; @@ -372,8 +370,6 @@ macro_rules! ns_export_each_flavor { { @ [ $($case:tt)* ] [$($infix:tt)*] $id:ident } => { paste::paste!{ - #[cfg(feature = "plain-consensus")] - #[cfg_attr(docsrs, doc(cfg(feature = "plain-consensus")))] pub use { plain ::$id as [] }; // unconditional pub use { md ::$id as [] }; diff --git a/crates/tor-netdoc/src/parse2.rs b/crates/tor-netdoc/src/parse2.rs index 1e08c9d408..948086df46 100644 --- a/crates/tor-netdoc/src/parse2.rs +++ b/crates/tor-netdoc/src/parse2.rs @@ -95,7 +95,7 @@ pub mod multiplicity; mod signatures; mod traits; -#[cfg(all(feature = "plain-consensus", feature = "incomplete"))] +#[cfg(feature = "incomplete")] pub mod poc; use internal_prelude::*; -- GitLab From f3283e7bd66ee099b1b537df1cb0b1c9fc80dfee Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 14:41:30 +0100 Subject: [PATCH 26/31] tor-netdoc: Un-gate RouterStatusMdDigestsVote and SoftwareVersion These are complete. Un-gate the RouterStatusMdDigestsVote implementation, and the export of both. --- crates/tor-netdoc/src/doc/netstatus.rs | 1 - crates/tor-netdoc/src/doc/netstatus/rs.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/crates/tor-netdoc/src/doc/netstatus.rs b/crates/tor-netdoc/src/doc/netstatus.rs index 17eedebcfc..4ea27ab1c0 100644 --- a/crates/tor-netdoc/src/doc/netstatus.rs +++ b/crates/tor-netdoc/src/doc/netstatus.rs @@ -117,7 +117,6 @@ pub use UncheckedPlainConsensus as UncheckedNsConsensus; #[deprecated] pub use UnvalidatedPlainConsensus as UnvalidatedNsConsensus; -#[cfg(feature = "ns-vote")] pub use rs::{RouterStatusMdDigestsVote, SoftwareVersion}; pub use dir_source::{ConsensusAuthoritySection, DirSource, SupersededAuthorityKey}; diff --git a/crates/tor-netdoc/src/doc/netstatus/rs.rs b/crates/tor-netdoc/src/doc/netstatus/rs.rs index c46627f8bd..657224768b 100644 --- a/crates/tor-netdoc/src/doc/netstatus/rs.rs +++ b/crates/tor-netdoc/src/doc/netstatus/rs.rs @@ -62,7 +62,6 @@ static OTHER_VERSION_CACHE: InternCache = InternCache::new(); /// * These non-invariants apply both within one instance of this struct, /// and across multiple instances of it within a `RouterStatus`. #[derive(Debug, Clone, Default, Eq, PartialEq, Deftly)] -#[cfg(feature = "ns-vote")] #[derive_deftly(ItemValueParseable)] #[non_exhaustive] pub struct RouterStatusMdDigestsVote { -- GitLab From f7d94cfb32c98307f4dc136ca410d83a1a97d1ce Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 14:47:12 +0100 Subject: [PATCH 27/31] tor-netdoc: Un-gate test2 module Everything that this needs is un-gated now. --- crates/tor-netdoc/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/tor-netdoc/src/lib.rs b/crates/tor-netdoc/src/lib.rs index 075aba4596..d20e980dec 100644 --- a/crates/tor-netdoc/src/lib.rs +++ b/crates/tor-netdoc/src/lib.rs @@ -63,7 +63,7 @@ pub mod doc; mod err; pub mod types; -#[cfg(all(test, feature = "parse2", feature = "encode"))] +#[cfg(test)] mod test2; #[doc(hidden)] -- GitLab From f5aef395d597e877464125e26399ed94ac2ba540 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 14:41:40 +0100 Subject: [PATCH 28/31] tor-netdoc: Gate vote-related incomplete code with "incomplete" Change "ns-vote" gates to "incomplete": * `vote` modules, and in the variety macro. (And make a TODO more likely to be found.) Change "parse2" gates to "incomplete": * VoteAuthoritySection --- crates/tor-netdoc/src/doc/authcert.rs | 2 +- crates/tor-netdoc/src/doc/authcert/encoded.rs | 2 +- crates/tor-netdoc/src/doc/netstatus.rs | 10 +++++----- crates/tor-netdoc/src/doc/netstatus/rs.rs | 2 +- .../tor-netdoc/src/doc/ns_variety_definition_macros.rs | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/tor-netdoc/src/doc/authcert.rs b/crates/tor-netdoc/src/doc/authcert.rs index 2ac66ee20a..0021b8809b 100644 --- a/crates/tor-netdoc/src/doc/authcert.rs +++ b/crates/tor-netdoc/src/doc/authcert.rs @@ -677,7 +677,7 @@ impl AuthCert { /// as an [`EncodedAuthCert`]. // TODO these features are quite tangled // `EncodedAuthCert` is only available with `parse2` and `plain-consensus` - #[cfg(feature = "incomplete")] + #[cfg(feature = "incomplete")] // Needs EncodedAuthCert pub fn encode_sign(&self, k_auth_id_rsa: &rsa::KeyPair) -> StdResult { let mut encoder = NetdocEncoder::new(); self.encode_unsigned(&mut encoder)?; diff --git a/crates/tor-netdoc/src/doc/authcert/encoded.rs b/crates/tor-netdoc/src/doc/authcert/encoded.rs index 9ad0640159..74ec07e1a9 100644 --- a/crates/tor-netdoc/src/doc/authcert/encoded.rs +++ b/crates/tor-netdoc/src/doc/authcert/encoded.rs @@ -268,7 +268,7 @@ impl NetdocParseable for EncodedAuthCert { } } -#[cfg(feature = "encode")] // TODO get rid of this feature, and use imports rather than :: paths +// XXXX use imports rather than :: paths impl crate::encode::NetdocEncodable for EncodedAuthCert { fn encode_unsigned( &self, diff --git a/crates/tor-netdoc/src/doc/netstatus.rs b/crates/tor-netdoc/src/doc/netstatus.rs index 4ea27ab1c0..d0b839dd0b 100644 --- a/crates/tor-netdoc/src/doc/netstatus.rs +++ b/crates/tor-netdoc/src/doc/netstatus.rs @@ -53,7 +53,7 @@ mod rs; pub mod md; pub mod plain; -#[cfg(feature = "ns-vote")] +#[cfg(feature = "incomplete")] pub mod vote; #[cfg(feature = "build_docs")] @@ -694,7 +694,7 @@ define_derive_deftly! { ${defcond F_NORMAL not(fmeta(netdoc(skip)))} - #[cfg(feature = "parse2")] + #[cfg(feature = "incomplete")] // needs EncodedAuthCert, otherwise complete impl NetdocParseable for VoteAuthoritySection { fn doctype_for_error() -> &'static str { "vote.authority.section" @@ -730,7 +730,7 @@ define_derive_deftly! { } } - #[cfg(feature = "encode")] + #[cfg(feature = "incomplete")] impl NetdocEncodable for VoteAuthoritySection { fn encode_unsigned(&self, out: &mut NetdocEncoder) -> StdResult<(), Bug> { $( @@ -751,7 +751,7 @@ define_derive_deftly! { #[derive(Deftly, Clone, Debug)] #[derive_deftly(VoteAuthoritySection, Constructor)] #[allow(clippy::exhaustive_structs)] -#[cfg(feature = "parse2")] +#[cfg(feature = "incomplete")] // needs EncodedAuthCert, otherwise complete pub struct VoteAuthoritySection { /// Authority entry #[deftly(constructor)] @@ -1608,7 +1608,7 @@ mod test { //! use super::*; use hex_literal::hex; - #[cfg(all(feature = "ns-vote", feature = "parse2"))] + #[cfg(feature = "incomplete")] use { crate::parse2::{NetdocUnverified as _, ParseInput, parse_netdoc}, std::fs, diff --git a/crates/tor-netdoc/src/doc/netstatus/rs.rs b/crates/tor-netdoc/src/doc/netstatus/rs.rs index 657224768b..6175cd4b48 100644 --- a/crates/tor-netdoc/src/doc/netstatus/rs.rs +++ b/crates/tor-netdoc/src/doc/netstatus/rs.rs @@ -7,7 +7,7 @@ pub(crate) mod build; pub(crate) mod md; pub(crate) mod plain; -#[cfg(feature = "ns-vote")] +#[cfg(feature = "incomplete")] pub(crate) mod vote; use super::{ConsensusFlavor, ConsensusMethods, consensus_methods_comma_separated}; diff --git a/crates/tor-netdoc/src/doc/ns_variety_definition_macros.rs b/crates/tor-netdoc/src/doc/ns_variety_definition_macros.rs index adc4ac319a..4fa480f9b0 100644 --- a/crates/tor-netdoc/src/doc/ns_variety_definition_macros.rs +++ b/crates/tor-netdoc/src/doc/ns_variety_definition_macros.rs @@ -300,7 +300,7 @@ use ns_do_variety_md; /// Include variety-agnostic items, for a vote, from `each_variety.rs`. /// /// Use within `vote.rs`. -#[allow(unused)] // TODO feature = "ns-vote" +#[allow(unused)] // TODO DIRAUTH macro_rules! ns_do_variety_vote { {} => { ns_do_one_variety! { vote : plain md vote $ } } } #[cfg(doc)] use ns_do_variety_vote; @@ -342,8 +342,8 @@ macro_rules! ns_export_each_variety { pub use { plain ::$id as [] }; // unconditional pub use { md ::$id as [] }; - #[cfg(feature = "ns-vote")] // TODO ns-vote this feature doesn't exist yet - #[cfg_attr(docsrs, doc(cfg(feature = "ns-vote")))] + #[cfg(feature = "incomplete")] + #[cfg_attr(docsrs, doc(cfg(feature = "incomplete")))] pub use { vote::$id as [] }; } }; } -- GitLab From 4d4220e8a0fab3f1210a54ce1d3230b39ae7a89b Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 15:54:54 +0100 Subject: [PATCH 29/31] tor-netdoc: Gate vote-related incomplete code with "incomplete" (tidy) --- crates/tor-netdoc/src/doc/authcert/encoded.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/tor-netdoc/src/doc/authcert/encoded.rs b/crates/tor-netdoc/src/doc/authcert/encoded.rs index 74ec07e1a9..29a6c72956 100644 --- a/crates/tor-netdoc/src/doc/authcert/encoded.rs +++ b/crates/tor-netdoc/src/doc/authcert/encoded.rs @@ -1,7 +1,9 @@ //! `EncodedAuthCert` use std::str::FromStr; +use tor_error::Bug; +use crate::encode::{NetdocEncodable, NetdocEncoder}; use crate::parse2::{ ErrorProblem, IsStructural, ItemStream, KeywordRef, NetdocParseable, ParseInput, }; @@ -268,12 +270,11 @@ impl NetdocParseable for EncodedAuthCert { } } -// XXXX use imports rather than :: paths -impl crate::encode::NetdocEncodable for EncodedAuthCert { +impl NetdocEncodable for EncodedAuthCert { fn encode_unsigned( &self, - out: &mut crate::encode::NetdocEncoder, - ) -> Result<(), tor_error::Bug> { + out: &mut NetdocEncoder, + ) -> Result<(), Bug> { // OK because invariants include the right syntax including a trailing newline. out.push_raw_string(&self.as_str()); Ok(()) -- GitLab From a487c3f0b7eeee32c61e5306bfb6312364bbef9d Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 15:56:25 +0100 Subject: [PATCH 30/31] tor-netdoc: Gate vote-related incomplete code with "incomplete" (fmt) --- crates/tor-netdoc/src/doc/authcert/encoded.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/tor-netdoc/src/doc/authcert/encoded.rs b/crates/tor-netdoc/src/doc/authcert/encoded.rs index 29a6c72956..0a355429d7 100644 --- a/crates/tor-netdoc/src/doc/authcert/encoded.rs +++ b/crates/tor-netdoc/src/doc/authcert/encoded.rs @@ -271,10 +271,7 @@ impl NetdocParseable for EncodedAuthCert { } impl NetdocEncodable for EncodedAuthCert { - fn encode_unsigned( - &self, - out: &mut NetdocEncoder, - ) -> Result<(), Bug> { + fn encode_unsigned(&self, out: &mut NetdocEncoder) -> Result<(), Bug> { // OK because invariants include the right syntax including a trailing newline. out.push_raw_string(&self.as_str()); Ok(()) -- GitLab From 0c24cde148938149c8e45d56968e84d649d08974 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Apr 2026 15:56:54 +0100 Subject: [PATCH 31/31] tor-netdoc: Require "encode" feature from tor-cert This is needed because we don't have !3926 in main yet. It will produce a semantic conflict when that merges. --- crates/tor-netdoc/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/tor-netdoc/Cargo.toml b/crates/tor-netdoc/Cargo.toml index d4faae06bf..24606b318d 100644 --- a/crates/tor-netdoc/Cargo.toml +++ b/crates/tor-netdoc/Cargo.toml @@ -135,7 +135,7 @@ tinystr = "0.8.0" tor-basic-utils = { path = "../tor-basic-utils", version = "0.41.0" } tor-bytes = { path = "../tor-bytes", version = "0.41.0" } tor-cell = { path = "../tor-cell", version = "0.41.0" } -tor-cert = { path = "../tor-cert", version = "0.41.0" } +tor-cert = { path = "../tor-cert", version = "0.41.0", features = ["encode"] } tor-checkable = { path = "../tor-checkable", version = "0.41.0" } tor-error = { path = "../tor-error", version = "0.41.0" } tor-hscrypto = { path = "../tor-hscrypto", version = "0.41.0", optional = true } -- GitLab