Skip to content

Commit cb3ccd7

Browse files
simonwickyjstuczyn
authored andcommitted
use typed builder (#6150)
1 parent 16509db commit cb3ccd7

File tree

5 files changed

+28
-231
lines changed

5 files changed

+28
-231
lines changed

Cargo.lock

Lines changed: 22 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ tracing-indicatif = "0.3.9"
368368
tracing-test = "0.2.5"
369369
ts-rs = "10.1.0"
370370
tungstenite = { version = "0.20.1", default-features = false }
371+
typed-builder = "0.23.0"
371372
uniffi = "0.29.2"
372373
uniffi_build = "0.29.0"
373374
url = "2.5"

nym-registration-client/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ thiserror.workspace = true
1717
tokio.workspace = true
1818
tokio-util.workspace = true
1919
tracing.workspace = true
20+
typed-builder.workspace = true
2021
url.workspace = true
2122

2223
nym-authenticator-client = { path = "../nym-authenticator-client" }

nym-registration-client/src/builder/config.rs

Lines changed: 3 additions & 228 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use nym_sdk::{
1515
use std::os::fd::RawFd;
1616
use std::{path::PathBuf, sync::Arc, time::Duration};
1717
use tokio_util::sync::CancellationToken;
18+
use typed_builder::TypedBuilder;
1819

1920
use crate::error::RegistrationClientError;
2021

@@ -27,11 +28,13 @@ pub struct NymNodeWithKeys {
2728
pub keys: Arc<KeyPair>,
2829
}
2930

31+
#[derive(TypedBuilder)]
3032
pub struct BuilderConfig {
3133
pub entry_node: NymNodeWithKeys,
3234
pub exit_node: NymNodeWithKeys,
3335
pub data_path: Option<PathBuf>,
3436
pub mixnet_client_config: MixnetClientConfig,
37+
#[builder(default = MIXNET_CLIENT_STARTUP_TIMEOUT)]
3538
pub mixnet_client_startup_timeout: Duration,
3639
pub two_hops: bool,
3740
pub user_agent: UserAgent,
@@ -58,22 +61,6 @@ pub struct MixnetClientConfig {
5861
}
5962

6063
impl BuilderConfig {
61-
/// Creates a builder for BuilderConfig
62-
///
63-
/// This is the preferred way to construct a BuilderConfig.
64-
///
65-
/// # Example
66-
/// ```ignore
67-
/// let config = BuilderConfig::builder()
68-
/// .entry_node(entry)
69-
/// .exit_node(exit)
70-
/// .user_agent(agent)
71-
/// .build()?;
72-
/// ```
73-
pub fn builder() -> BuilderConfigBuilder {
74-
BuilderConfigBuilder::default()
75-
}
76-
7764
pub fn mixnet_client_debug_config(&self) -> DebugConfig {
7865
if self.two_hops {
7966
two_hop_debug_config(&self.mixnet_client_config)
@@ -225,168 +212,6 @@ fn true_to_disabled(val: bool) -> &'static str {
225212
if val { "disabled" } else { "enabled" }
226213
}
227214

228-
/// Error type for BuilderConfig validation
229-
#[derive(Debug, Clone, thiserror::Error)]
230-
#[allow(clippy::enum_variant_names)]
231-
pub enum BuilderConfigError {
232-
#[error("entry_node is required")]
233-
MissingEntryNode,
234-
#[error("exit_node is required")]
235-
MissingExitNode,
236-
#[error("mixnet_client_config is required")]
237-
MissingMixnetClientConfig,
238-
#[error("user_agent is required")]
239-
MissingUserAgent,
240-
#[error("custom_topology_provider is required")]
241-
MissingTopologyProvider,
242-
#[error("network_env is required")]
243-
MissingNetworkEnv,
244-
#[error("cancel_token is required")]
245-
MissingCancelToken,
246-
#[cfg(unix)]
247-
#[error("connection_fd_callback is required")]
248-
MissingConnectionFdCallback,
249-
}
250-
251-
/// Builder for `BuilderConfig`
252-
///
253-
/// This provides a more convenient way to construct a `BuilderConfig` compared to the
254-
/// `new()` constructor with many arguments.
255-
#[derive(Default)]
256-
pub struct BuilderConfigBuilder {
257-
entry_node: Option<NymNodeWithKeys>,
258-
exit_node: Option<NymNodeWithKeys>,
259-
data_path: Option<PathBuf>,
260-
mixnet_client_config: Option<MixnetClientConfig>,
261-
mixnet_client_startup_timeout: Duration,
262-
two_hops: bool,
263-
user_agent: Option<UserAgent>,
264-
custom_topology_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
265-
network_env: Option<NymNetworkDetails>,
266-
cancel_token: Option<CancellationToken>,
267-
#[cfg(unix)]
268-
connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
269-
}
270-
271-
impl BuilderConfigBuilder {
272-
pub fn new() -> Self {
273-
Self {
274-
mixnet_client_startup_timeout: MIXNET_CLIENT_STARTUP_TIMEOUT,
275-
..Default::default()
276-
}
277-
}
278-
279-
#[must_use]
280-
pub fn entry_node(mut self, entry_node: NymNodeWithKeys) -> Self {
281-
self.entry_node = Some(entry_node);
282-
self
283-
}
284-
285-
#[must_use]
286-
pub fn exit_node(mut self, exit_node: NymNodeWithKeys) -> Self {
287-
self.exit_node = Some(exit_node);
288-
self
289-
}
290-
291-
#[must_use]
292-
pub fn data_path(mut self, data_path: Option<PathBuf>) -> Self {
293-
self.data_path = data_path;
294-
self
295-
}
296-
297-
#[must_use]
298-
pub fn mixnet_client_config(mut self, mixnet_client_config: MixnetClientConfig) -> Self {
299-
self.mixnet_client_config = Some(mixnet_client_config);
300-
self
301-
}
302-
303-
#[must_use]
304-
pub fn mixnet_client_startup_timeout(
305-
mut self,
306-
mixnet_client_startup_timeout: Duration,
307-
) -> Self {
308-
self.mixnet_client_startup_timeout = mixnet_client_startup_timeout;
309-
self
310-
}
311-
312-
#[must_use]
313-
pub fn two_hops(mut self, two_hops: bool) -> Self {
314-
self.two_hops = two_hops;
315-
self
316-
}
317-
318-
#[must_use]
319-
pub fn user_agent(mut self, user_agent: UserAgent) -> Self {
320-
self.user_agent = Some(user_agent);
321-
self
322-
}
323-
324-
#[must_use]
325-
pub fn custom_topology_provider(
326-
mut self,
327-
custom_topology_provider: Box<dyn TopologyProvider + Send + Sync>,
328-
) -> Self {
329-
self.custom_topology_provider = Some(custom_topology_provider);
330-
self
331-
}
332-
333-
#[must_use]
334-
pub fn network_env(mut self, network_env: NymNetworkDetails) -> Self {
335-
self.network_env = Some(network_env);
336-
self
337-
}
338-
339-
#[must_use]
340-
pub fn cancel_token(mut self, cancel_token: CancellationToken) -> Self {
341-
self.cancel_token = Some(cancel_token);
342-
self
343-
}
344-
345-
#[cfg(unix)]
346-
#[must_use]
347-
pub fn connection_fd_callback(
348-
mut self,
349-
connection_fd_callback: Arc<dyn Fn(RawFd) + Send + Sync>,
350-
) -> Self {
351-
self.connection_fd_callback = Some(connection_fd_callback);
352-
self
353-
}
354-
355-
/// Builds the `BuilderConfig`.
356-
///
357-
/// Returns an error if any required field is missing.
358-
pub fn build(self) -> Result<BuilderConfig, BuilderConfigError> {
359-
Ok(BuilderConfig {
360-
entry_node: self
361-
.entry_node
362-
.ok_or(BuilderConfigError::MissingEntryNode)?,
363-
exit_node: self.exit_node.ok_or(BuilderConfigError::MissingExitNode)?,
364-
data_path: self.data_path,
365-
mixnet_client_config: self
366-
.mixnet_client_config
367-
.ok_or(BuilderConfigError::MissingMixnetClientConfig)?,
368-
mixnet_client_startup_timeout: self.mixnet_client_startup_timeout,
369-
two_hops: self.two_hops,
370-
user_agent: self
371-
.user_agent
372-
.ok_or(BuilderConfigError::MissingUserAgent)?,
373-
custom_topology_provider: self
374-
.custom_topology_provider
375-
.ok_or(BuilderConfigError::MissingTopologyProvider)?,
376-
network_env: self
377-
.network_env
378-
.ok_or(BuilderConfigError::MissingNetworkEnv)?,
379-
cancel_token: self
380-
.cancel_token
381-
.ok_or(BuilderConfigError::MissingCancelToken)?,
382-
#[cfg(unix)]
383-
connection_fd_callback: self
384-
.connection_fd_callback
385-
.ok_or(BuilderConfigError::MissingConnectionFdCallback)?,
386-
})
387-
}
388-
}
389-
390215
#[cfg(test)]
391216
mod tests {
392217
use super::*;
@@ -399,54 +224,4 @@ mod tests {
399224
assert_eq!(config.min_mixnode_performance, None);
400225
assert_eq!(config.min_gateway_performance, None);
401226
}
402-
403-
#[test]
404-
fn test_builder_config_builder_fails_without_required_fields() {
405-
// Building without any fields should fail with specific error
406-
let result = BuilderConfig::builder().build();
407-
assert!(result.is_err());
408-
match result {
409-
Err(BuilderConfigError::MissingEntryNode) => (), // Expected
410-
Err(e) => panic!("Expected MissingEntryNode, got: {}", e),
411-
Ok(_) => panic!("Expected error, got Ok"),
412-
}
413-
}
414-
415-
#[test]
416-
fn test_builder_config_builder_validates_all_required_fields() {
417-
// Test that each required field is validated
418-
let result = BuilderConfig::builder().build();
419-
assert!(result.is_err());
420-
421-
// Short-circuits at first missing field, so we just verify it's one of the expected errors
422-
#[allow(unreachable_patterns)] // All variants are covered, but keeping catch-all for safety
423-
match result {
424-
Err(BuilderConfigError::MissingEntryNode)
425-
| Err(BuilderConfigError::MissingExitNode)
426-
| Err(BuilderConfigError::MissingMixnetClientConfig)
427-
| Err(BuilderConfigError::MissingUserAgent)
428-
| Err(BuilderConfigError::MissingTopologyProvider)
429-
| Err(BuilderConfigError::MissingNetworkEnv)
430-
| Err(BuilderConfigError::MissingCancelToken) => (),
431-
#[cfg(unix)]
432-
Err(BuilderConfigError::MissingConnectionFdCallback) => (),
433-
Err(e) => panic!("Unexpected error: {}", e),
434-
Ok(_) => panic!("Expected validation error, got Ok"),
435-
}
436-
}
437-
438-
#[test]
439-
fn test_builder_config_builder_method_chaining() {
440-
// Test that builder methods chain properly and return Self
441-
let builder = BuilderConfig::builder();
442-
443-
// Verify the builder returns itself for chaining
444-
let builder = builder.two_hops(true);
445-
let builder = builder.two_hops(false);
446-
let builder = builder.data_path(None);
447-
448-
// Builder should still fail because required fields are missing
449-
let result = builder.build();
450-
assert!(result.is_err());
451-
}
452227
}

nym-registration-client/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ mod types;
1919

2020
pub use builder::RegistrationClientBuilder;
2121
pub use builder::config::{
22-
BuilderConfig as RegistrationClientBuilderConfig,
23-
BuilderConfigBuilder as RegistrationClientBuilderConfigBuilder, MixnetClientConfig,
22+
BuilderConfig as RegistrationClientBuilderConfig, MixnetClientConfig,
2423
NymNodeWithKeys as RegistrationNymNode,
2524
};
2625
pub use error::RegistrationClientError;

0 commit comments

Comments
 (0)