Skip to content

Commit 70f13b6

Browse files
authored
refactor(data-plane): replace encoder::Name with ProtoName throughout (agntcy#1596)
## Description Removes the `encoder::Name` struct entirely and replaces it with `ProtoName` (the prost-generated protobuf message type) across all crates in the data plane. `encoder::Name` was a conversion shim between human-readable string components and the 4×u64 XxHash64-encoded wire representation (`EncodedName`). Every message already carried a `ProtoName` directly in its `SlimHeader`, making `Name` a pure overhead layer: code would convert `ProtoName → Name` to get ergonomic helpers (`from_strings`, `with_id`, etc.), then immediately convert `Name → ProtoName` before sending. ### What changed **`ProtoName` gains constructor/utility methods** (added to `api.rs`): - `from_strings([s0, s1, s2])` — hashes components via XxHash64 and stores both the encoded and string forms - `with_id(u64)`, `id()`, `has_id()`, `set_id()`, `reset_id()` — manage the 4th component (instance ID) - `match_prefix()` — compare first 3 components, ignoring ID (used for subscription prefix matching) - `str_components() -> (&str, &str, &str)` — access human-readable components - `NULL_COMPONENT` / `is_reserved_id()` — sentinel value for unset IDs **Routing hot path** — `ProtoName → EncodedName` is now a direct field access (`name.name.unwrap()`), with no intermediate `Name` allocation. All routing table keys are `EncodedName` (a `Copy` + `Hash` + `Eq` 4×u64 struct). **Collection types** — `HashMap<Name, _>` / `HashSet<Name>` across session, service, and controller crates are replaced with `HashMap<EncodedName, _>` / `HashSet<EncodedName>` for hot-path collections, and `HashMap<ProtoName, _>` where the full name is needed as a value. **`SlimHeader` constructor** — the `new_from_protos(ProtoName, ProtoName, ...)` / `new(&ProtoName, &ProtoName, ...)` split is collapsed into a single `new(ProtoName, ProtoName, ...)` that owns its arguments directly. **Bindings** — the `Name` UniFFI wrapper in `bindings/rust/src/name.rs` now holds a `ProtoName` directly rather than converting to/from `encoder::Name`. **`encoder.rs`** — the `Name` struct, all its `From` impls, and the re-exports in `messages/mod.rs` are removed. The file retains only `calculate_hash` (used internally by `ProtoName::from_strings`). ### Scope 68 files changed across `datapath`, `session`, `service`, `controller`, `bindings/rust`, `slimctl`, `testing`, and `examples`. ## Type of Change - [ ] Bugfix - [x] New Feature - [ ] Breaking Change - [x] Refactor - [ ] Documentation - [ ] Other (please describe) ## Checklist - [x] I have read the [contributing guidelines](/agntcy/repo-template/blob/main/CONTRIBUTING.md) - [ ] Existing issues have been referenced (where applicable) - [x] I have verified this change is not present in other open pull requests - [ ] Functionality is documented - [x] All code style checks pass - [x] New code contribution is covered by automated tests - [x] All new and existing tests pass --------- Signed-off-by: Sam Betts <1769706+Tehsmash@users.noreply.github.com>
1 parent 93eb621 commit 70f13b6

62 files changed

Lines changed: 1295 additions & 1430 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

data-plane/bindings/rust/src/app.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use slim_auth::auth_provider::{AuthProvider, AuthVerifier};
2727
use crate::identity_config::{IdentityProviderConfig, IdentityVerifierConfig};
2828

2929
use futures_timer::Delay;
30-
use slim_datapath::messages::Name as SlimName;
30+
use slim_datapath::api::ProtoName as SlimName;
3131
use slim_service::Service as SlimService;
3232
use slim_service::app::App as SlimApp;
3333
use slim_session::Direction as CoreDirection;
@@ -678,7 +678,7 @@ mod tests {
678678
use super::*;
679679

680680
use slim_config::component::ComponentBuilder;
681-
use slim_datapath::messages::Name as SlimName;
681+
use slim_datapath::api::ProtoName as SlimName;
682682
use slim_testing::utils::TEST_VALID_SECRET;
683683

684684
// Helper to create test identity configs

data-plane/bindings/rust/src/message_context.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
use std::collections::HashMap;
55
use std::sync::Arc;
66

7+
use slim_datapath::api::ProtoName as SlimName;
78
use slim_datapath::api::{ProtoMessage, ProtoPublishType};
8-
use slim_datapath::messages::Name as SlimName;
99

1010
use slim_session::SessionError;
1111

@@ -150,8 +150,8 @@ mod tests {
150150
let content = ApplicationPayload::new(&content_type, payload).as_content();
151151

152152
let mut slim_header = SlimHeader::default();
153-
slim_header.set_source(&source);
154-
slim_header.set_destination(&dest);
153+
slim_header.set_source(source);
154+
slim_header.set_destination(dest);
155155

156156
let publish = ProtoPublish {
157157
header: Some(slim_header),
@@ -272,8 +272,8 @@ mod tests {
272272

273273
// Create ProtoPublish without msg content
274274
let mut slim_header = SlimHeader::default();
275-
slim_header.set_source(&source_slim);
276-
slim_header.set_destination(&dest_slim);
275+
slim_header.set_source(source_slim);
276+
slim_header.set_destination(dest_slim);
277277

278278
let publish = ProtoPublish {
279279
header: Some(slim_header),

data-plane/bindings/rust/src/name.rs

Lines changed: 48 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,37 @@
33

44
use std::fmt::Display;
55

6-
use slim_datapath::messages::Name as SlimName;
6+
use slim_datapath::api::ProtoName;
77

88
use crate::errors::SlimError;
99

1010
/// Name type for SLIM (Secure Low-Latency Interactive Messaging)
1111
#[derive(Debug, Clone, PartialEq, uniffi::Object)]
1212
#[uniffi::export(Display, Debug, Eq)]
1313
pub struct Name {
14-
inner: SlimName,
14+
inner: ProtoName,
1515
}
1616

17-
impl From<Name> for SlimName {
17+
impl From<Name> for ProtoName {
1818
fn from(name: Name) -> Self {
1919
name.inner.clone()
2020
}
2121
}
2222

23-
impl From<&Name> for SlimName {
23+
impl From<&Name> for ProtoName {
2424
fn from(name: &Name) -> Self {
2525
name.inner.clone()
2626
}
2727
}
2828

29-
impl From<SlimName> for Name {
30-
fn from(name: SlimName) -> Self {
29+
impl From<ProtoName> for Name {
30+
fn from(name: ProtoName) -> Self {
3131
Name { inner: name }
3232
}
3333
}
3434

35-
impl From<&SlimName> for Name {
36-
fn from(name: &SlimName) -> Self {
35+
impl From<&ProtoName> for Name {
36+
fn from(name: &ProtoName) -> Self {
3737
Name {
3838
inner: name.clone(),
3939
}
@@ -42,7 +42,8 @@ impl From<&SlimName> for Name {
4242

4343
impl Display for Name {
4444
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45-
write!(f, "{}", self.inner)
45+
let (c0, c1, c2) = self.inner.str_components();
46+
write!(f, "{}/{}/{}", c0, c1, c2)
4647
}
4748
}
4849

@@ -51,7 +52,7 @@ impl Name {
5152
/// Create a new Name from components without an ID
5253
#[uniffi::constructor]
5354
pub fn new(component0: String, component1: String, component2: String) -> Self {
54-
let inner = SlimName::from_strings([component0, component1, component2]);
55+
let inner = ProtoName::from_strings([component0, component1, component2]);
5556
Name { inner }
5657
}
5758

@@ -74,7 +75,7 @@ impl Name {
7475
});
7576
}
7677
Ok(Name {
77-
inner: SlimName::from_strings([parts[0], parts[1], parts[2]]),
78+
inner: ProtoName::from_strings([parts[0], parts[1], parts[2]]),
7879
})
7980
}
8081

@@ -86,16 +87,17 @@ impl Name {
8687
component2: String,
8788
id: u64,
8889
) -> Self {
89-
if SlimName::is_reserved_id(id) {
90+
if ProtoName::is_reserved_id(id) {
9091
panic!("id {id:#x} is a reserved sentinel value and cannot be used as a name id");
9192
}
92-
let inner = SlimName::from_strings([component0, component1, component2]).with_id(id);
93+
let inner = ProtoName::from_strings([component0, component1, component2]).with_id(id);
9394
Name { inner }
9495
}
9596

9697
/// Get the name components as a vector of strings
9798
pub fn components(&self) -> Vec<String> {
98-
self.inner.components_strings().to_vec()
99+
let (c0, c1, c2) = self.inner.str_components();
100+
vec![c0.to_string(), c1.to_string(), c2.to_string()]
99101
}
100102

101103
/// Get the name ID
@@ -105,21 +107,14 @@ impl Name {
105107
}
106108

107109
impl Name {
108-
/// Get the name components as a reference (for internal Rust use only, not exposed to FFI)
109-
///
110-
/// This avoids copying when used internally in Rust code.
111-
pub fn components_ref(&self) -> &[String; 3] {
112-
self.inner.components_strings()
113-
}
114-
115-
/// Convert to SlimName (for internal Rust use only, not exposed to FFI)
116-
pub fn as_slim_name(&self) -> SlimName {
110+
/// Get the inner ProtoName (for internal Rust use only)
111+
pub fn as_slim_name(&self) -> ProtoName {
117112
self.inner.clone()
118113
}
119114

120-
/// Create from SlimName (for internal Rust use only, not exposed to FFI)
121-
pub fn from_slim_name(slim_name: SlimName) -> Self {
122-
Name { inner: slim_name }
115+
/// Create from ProtoName (for internal Rust use only)
116+
pub fn from_slim_name(proto_name: ProtoName) -> Self {
117+
Name { inner: proto_name }
123118
}
124119
}
125120

@@ -131,7 +126,7 @@ mod tests {
131126
// Name Conversion Tests
132127
// ========================================================================
133128

134-
/// Test Name to SlimName conversion with full components
129+
/// Test Name to ProtoName conversion with full components
135130
#[test]
136131
fn test_name_to_slim_name_full() {
137132
let name = Name::new_with_id(
@@ -141,47 +136,47 @@ mod tests {
141136
12345,
142137
);
143138

144-
let slim_name: SlimName = name.into();
145-
let components = slim_name.components_strings();
139+
let proto_name: ProtoName = name.into();
140+
let (c0, c1, c2) = proto_name.str_components();
146141

147-
assert_eq!(components[0], "org");
148-
assert_eq!(components[1], "namespace");
149-
assert_eq!(components[2], "app");
150-
assert_eq!(slim_name.id(), 12345);
142+
assert_eq!(c0, "org");
143+
assert_eq!(c1, "namespace");
144+
assert_eq!(c2, "app");
145+
assert_eq!(proto_name.id(), 12345);
151146
}
152147

153-
/// Test Name to SlimName conversion with partial components
148+
/// Test Name to ProtoName conversion with partial components
154149
#[test]
155150
fn test_name_to_slim_name_partial() {
156151
let name = Name::new("org".to_string(), "".to_string(), "".to_string());
157152

158-
let slim_name: SlimName = name.into();
159-
let components = slim_name.components_strings();
153+
let proto_name: ProtoName = name.into();
154+
let (c0, c1, c2) = proto_name.str_components();
160155

161-
assert_eq!(components[0], "org");
162-
assert_eq!(components[1], "");
163-
assert_eq!(components[2], "");
156+
assert_eq!(c0, "org");
157+
assert_eq!(c1, "");
158+
assert_eq!(c2, "");
164159
}
165160

166-
/// Test Name to SlimName conversion with empty components
161+
/// Test Name to ProtoName conversion with empty components
167162
#[test]
168163
fn test_name_to_slim_name_empty() {
169164
let name = Name::new("".to_string(), "".to_string(), "".to_string());
170165

171-
let slim_name: SlimName = name.into();
172-
let components = slim_name.components_strings();
166+
let proto_name: ProtoName = name.into();
167+
let (c0, c1, c2) = proto_name.str_components();
173168

174-
assert_eq!(components[0], "");
175-
assert_eq!(components[1], "");
176-
assert_eq!(components[2], "");
169+
assert_eq!(c0, "");
170+
assert_eq!(c1, "");
171+
assert_eq!(c2, "");
177172
}
178173

179-
/// Test SlimName to Name conversion
174+
/// Test ProtoName to Name conversion
180175
#[test]
181176
fn test_slim_name_to_name() {
182-
let slim_name = SlimName::from_strings(["org", "namespace", "app"]).with_id(54321);
177+
let proto_name = ProtoName::from_strings(["org", "namespace", "app"]).with_id(54321);
183178

184-
let name = Name::from(&slim_name);
179+
let name = Name::from(&proto_name);
185180

186181
assert_eq!(name.components(), vec!["org", "namespace", "app"]);
187182
assert_eq!(name.id(), 54321);
@@ -197,8 +192,8 @@ mod tests {
197192
99999,
198193
);
199194

200-
let slim_name: SlimName = original.clone().into();
201-
let converted = Name::from(&slim_name);
195+
let proto_name: ProtoName = original.clone().into();
196+
let converted = Name::from(&proto_name);
202197

203198
assert_eq!(original.components(), converted.components());
204199
assert_eq!(original.id(), converted.id());
@@ -238,7 +233,7 @@ mod tests {
238233
);
239234
let display_str = format!("{}", name);
240235

241-
// Should display the SlimName format
236+
// Should display the ProtoName format
242237
assert!(!display_str.is_empty());
243238
}
244239

@@ -250,8 +245,8 @@ mod tests {
250245
assert_eq!(name_with_id.id(), 42);
251246

252247
let name_without_id = Name::new("org".to_string(), "ns".to_string(), "app".to_string());
253-
// SlimName generates a default ID, so it should be non-zero
254-
assert!(name_without_id.id() > 0);
248+
// ProtoName without with_id sets component_3 to NULL_COMPONENT
249+
assert_eq!(name_without_id.id(), ProtoName::NULL_COMPONENT);
255250
}
256251

257252
/// Test Name::from_string with a valid input

data-plane/bindings/rust/src/service.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use slim_config::component::id::{ID, Kind};
1919
use slim_config::grpc::client::ClientConfig as CoreClientConfig;
2020
use slim_config::grpc::server::ServerConfig as CoreServerConfig;
2121
use slim_controller::config::Config as CoreControllerConfig;
22-
use slim_datapath::messages::Name as SlimName;
22+
use slim_datapath::api::ProtoName as SlimName;
2323
use slim_service::{
2424
KIND, Service as SlimService, ServiceConfiguration as SlimServiceConfiguration,
2525
};
@@ -515,7 +515,7 @@ pub fn create_service_with_config(
515515
#[cfg(test)]
516516
mod tests {
517517
use super::*;
518-
use slim_datapath::messages::Name as SlimName;
518+
use slim_datapath::api::ProtoName as SlimName;
519519
use slim_testing::utils::TEST_VALID_SECRET;
520520

521521
use crate::app::App;

data-plane/bindings/rust/src/session.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use std::sync::Arc;
88
use tokio::sync::RwLock;
99

1010
use futures_timer::Delay;
11+
use slim_datapath::api::ProtoName as SlimName;
1112
use slim_datapath::api::ProtoSessionType;
12-
use slim_datapath::messages::Name as SlimName;
1313
use slim_datapath::messages::utils::{PUBLISH_TO, SlimHeaderFlags, TRUE_VAL};
1414
use slim_session::SessionConfig as SlimSessionConfig;
1515
use slim_session::SessionError;
@@ -735,8 +735,8 @@ mod tests {
735735
let content = ApplicationPayload::new(content_type, payload).as_content();
736736

737737
let mut slim_header = SlimHeader::default();
738-
slim_header.set_source(&source);
739-
slim_header.set_destination(&dest);
738+
slim_header.set_source(source);
739+
slim_header.set_destination(dest);
740740

741741
let publish = ProtoPublish {
742742
header: Some(slim_header),
@@ -1346,10 +1346,10 @@ mod tests {
13461346
);
13471347

13481348
let slim_name = message_ctx.source_as_slim_name();
1349-
let components = slim_name.components_strings();
1350-
assert_eq!(components[0], "org");
1351-
assert_eq!(components[1], "namespace");
1352-
assert_eq!(components[2], "app");
1349+
let (c0, c1, c2) = slim_name.str_components();
1350+
assert_eq!(c0, "org");
1351+
assert_eq!(c1, "namespace");
1352+
assert_eq!(c2, "app");
13531353
}
13541354

13551355
// ==================== Empty/Edge Case Tests ====================

data-plane/bindings/rust/src/slimrpc.rs

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
//! This crate works directly with core SLIM types:
2323
//! - `slim_service::app::App` - The SLIM application instance
2424
//! - `slim_session::context::SessionContext` - Session context for RPC calls
25-
//! - `slim_datapath::messages::Name` - SLIM names for service addressing
25+
//! - `slim_datapath::api::ProtoName` - SLIM names for service addressing
2626
//!
2727
//! ## Client Example
2828
//!
@@ -92,7 +92,7 @@
9292
//! # }
9393
//! ```
9494
95-
use slim_datapath::messages::Name;
95+
use slim_datapath::api::ProtoName as Name;
9696

9797
/// Build a method-specific subscription name (base-service-method)
9898
///
@@ -111,22 +111,12 @@ pub fn build_method_subscription_name(
111111
service_name: &str,
112112
method_name: &str,
113113
) -> Name {
114-
let components_strings = base_name.components_strings();
115-
if components_strings.len() < 3 {
116-
panic!("Base name must have at least 3 components");
117-
}
114+
let (c0, c1, c2) = base_name.str_components();
118115

119116
// Create subscription name: org/namespace/app-service-method
120-
let app_with_method = format!(
121-
"{}-{}-{}",
122-
&components_strings[2], service_name, method_name
123-
);
117+
let app_with_method = format!("{}-{}-{}", c2, service_name, method_name);
124118

125-
Name::from_strings([
126-
components_strings[0].clone(),
127-
components_strings[1].clone(),
128-
app_with_method,
129-
])
119+
Name::from_strings([c0, c1, &app_with_method])
130120
}
131121

132122
mod channel;

0 commit comments

Comments
 (0)