@@ -26,13 +26,24 @@ use ahash::{AHashMap, AHashSet};
26
26
use handler:: ShareableMessageHandler ;
27
27
use indexmap:: IndexMap ;
28
28
use matching:: is_matching_backtracking;
29
- use nautilus_core:: UUID4 ;
29
+ use nautilus_core:: {
30
+ UUID4 ,
31
+ correctness:: { FAILED , check_predicate_true, check_valid_string} ,
32
+ } ;
30
33
use nautilus_model:: identifiers:: TraderId ;
31
34
use switchboard:: MessagingSwitchboard ;
32
35
use ustr:: Ustr ;
33
36
34
37
use super :: { handler, matching, set_message_bus, switchboard} ;
35
38
39
+ #[ inline( always) ]
40
+ fn check_fully_qualified_string ( value : & Ustr , key : & str ) -> anyhow:: Result < ( ) > {
41
+ check_predicate_true (
42
+ !value. chars ( ) . any ( |c| c == '*' || c == '?' ) ,
43
+ & format ! ( "{key} `value` contained invalid characters, was {value}" ) ,
44
+ )
45
+ }
46
+
36
47
/// A string pattern for a subscription. The pattern is used to match topics.
37
48
///
38
49
/// A pattern is made of characters:
@@ -80,20 +91,29 @@ impl From<&Topic> for Pattern {
80
91
pub struct Topic ( pub Ustr ) ;
81
92
82
93
impl Topic {
83
- pub fn as_pattern ( & self ) -> Pattern {
84
- Pattern ( self . 0 )
94
+ /// Creates a new [`Topic`] instance.
95
+ ///
96
+ /// # Errors
97
+ ///
98
+ /// Returns an error if:
99
+ /// - `value` string is empty, all whitespace, or contains non-ASCII characters.
100
+ /// - `value` string contains wildcard characters '*' or '?'.
101
+ pub fn new < T : AsRef < str > > ( value : T ) -> anyhow:: Result < Self > {
102
+ let topic = Ustr :: from ( value. as_ref ( ) ) ;
103
+ check_valid_string ( value, stringify ! ( value) ) ?;
104
+ check_fully_qualified_string ( & topic, stringify ! ( Topic ) ) ?;
105
+
106
+ Ok ( Self ( topic) )
85
107
}
86
108
87
- // TODO: Every initialization should validate
88
- pub fn validate < T : AsRef < str > > ( topic : T ) -> bool {
89
- let topic = Ustr :: from ( topic. as_ref ( ) ) ;
90
- !topic. chars ( ) . any ( |c| c == '*' || c == '?' )
109
+ pub fn as_pattern ( & self ) -> Pattern {
110
+ Pattern ( self . 0 )
91
111
}
92
112
}
93
113
94
114
impl < T : AsRef < str > > From < T > for Topic {
95
115
fn from ( value : T ) -> Self {
96
- Self ( Ustr :: from ( value. as_ref ( ) ) )
116
+ Self :: new ( value) . expect ( FAILED )
97
117
}
98
118
}
99
119
@@ -118,16 +138,25 @@ impl Display for Topic {
118
138
pub struct Endpoint ( pub Ustr ) ;
119
139
120
140
impl Endpoint {
121
- // TODO: Every initialization should validate
122
- pub fn validate < T : AsRef < str > > ( endpoint : T ) -> bool {
123
- let endpoint = Ustr :: from ( endpoint. as_ref ( ) ) ;
124
- !endpoint. chars ( ) . any ( |c| c == '*' || c == '?' )
141
+ /// Creates a new [`Endpoint`] instance.
142
+ ///
143
+ /// # Errors
144
+ ///
145
+ /// Returns an error if:
146
+ /// - `value` string is empty, all whitespace, or contains non-ASCII characters.
147
+ /// - `value` string contains wildcard characters '*' or '?'.
148
+ pub fn new < T : AsRef < str > > ( value : T ) -> anyhow:: Result < Self > {
149
+ let endpoint = Ustr :: from ( value. as_ref ( ) ) ;
150
+ check_valid_string ( value, stringify ! ( value) ) ?;
151
+ check_fully_qualified_string ( & endpoint, stringify ! ( Endpoint ) ) ?;
152
+
153
+ Ok ( Self ( endpoint) )
125
154
}
126
155
}
127
156
128
157
impl < T : AsRef < str > > From < T > for Endpoint {
129
158
fn from ( value : T ) -> Self {
130
- Self ( Ustr :: from ( value. as_ref ( ) ) )
159
+ Self :: new ( value) . expect ( FAILED )
131
160
}
132
161
}
133
162
@@ -305,12 +334,12 @@ impl MessageBus {
305
334
. collect ( )
306
335
}
307
336
308
- /// Returns whether there are subscribers for the given `topic`.
337
+ /// Returns whether there are subscribers for the `topic`.
309
338
pub fn has_subscribers < T : AsRef < str > > ( & self , topic : T ) -> bool {
310
339
self . subscriptions_count ( topic) > 0
311
340
}
312
341
313
- /// Returns the count of subscribers for the given `topic`.
342
+ /// Returns the count of subscribers for the `topic`.
314
343
#[ must_use]
315
344
pub fn subscriptions_count < T : AsRef < str > > ( & self , topic : T ) -> usize {
316
345
let topic = Topic :: from ( topic) ;
@@ -335,14 +364,14 @@ impl MessageBus {
335
364
. collect ( )
336
365
}
337
366
338
- /// Returns whether there is a registered endpoint for the given `pattern`.
367
+ /// Returns whether there is a registered endpoint for the `pattern`.
339
368
#[ must_use]
340
369
pub fn is_registered < T : AsRef < str > > ( & self , endpoint : T ) -> bool {
341
370
self . endpoints
342
371
. contains_key ( & Endpoint :: from ( endpoint. as_ref ( ) ) )
343
372
}
344
373
345
- /// Returns whether the given `handler` is subscribed to the given `pattern`.
374
+ /// Returns whether the `handler` is subscribed to the `pattern`.
346
375
#[ must_use]
347
376
pub fn is_subscribed < T : AsRef < str > > (
348
377
& self ,
@@ -358,25 +387,25 @@ impl MessageBus {
358
387
///
359
388
/// # Errors
360
389
///
361
- /// This function never returns an error (TBD).
390
+ /// This function never returns an error (TBD once backing database added ).
362
391
pub const fn close ( & self ) -> anyhow:: Result < ( ) > {
363
392
// TODO: Integrate the backing database
364
393
Ok ( ( ) )
365
394
}
366
395
367
- /// Returns the handler for the given `endpoint`.
396
+ /// Returns the handler for the `endpoint`.
368
397
#[ must_use]
369
398
pub fn get_endpoint ( & self , endpoint : & Endpoint ) -> Option < & ShareableMessageHandler > {
370
399
self . endpoints . get ( endpoint)
371
400
}
372
401
373
- /// Returns the handler for the given `correlation_id`.
402
+ /// Returns the handler for the `correlation_id`.
374
403
#[ must_use]
375
404
pub fn get_response_handler ( & self , correlation_id : & UUID4 ) -> Option < & ShareableMessageHandler > {
376
405
self . correlation_index . get ( correlation_id)
377
406
}
378
407
379
- /// Finds the subscriptions with pattern matching the given `topic`.
408
+ /// Finds the subscriptions with pattern matching the `topic`.
380
409
pub ( crate ) fn find_topic_matches ( & self , topic : & Topic ) -> Vec < Subscription > {
381
410
self . subscriptions
382
411
. iter ( )
@@ -390,7 +419,7 @@ impl MessageBus {
390
419
. collect ( )
391
420
}
392
421
393
- /// Finds the subscriptions which match the given `topic` and caches the
422
+ /// Finds the subscriptions which match the `topic` and caches the
394
423
/// results in the `patterns` map.
395
424
#[ must_use]
396
425
pub fn matching_subscriptions < T : AsRef < str > > ( & mut self , topic : T ) -> Vec < Subscription > {
@@ -411,7 +440,7 @@ impl MessageBus {
411
440
///
412
441
/// # Errors
413
442
///
414
- /// Returns an error if a handler is already registered for the given correlation ID .
443
+ /// Returns an error if ` handler` is already registered for the `correlation_id` .
415
444
pub fn register_response_handler (
416
445
& mut self ,
417
446
correlation_id : & UUID4 ,
0 commit comments