@@ -16,7 +16,8 @@ use crate::{
16
16
17
17
#[ derive( Debug , Clone , PartialEq , Eq , Hash , Serialize , Deserialize ) ]
18
18
#[ serde( rename_all = "camelCase" ) ]
19
- pub struct LatestPriceRequest {
19
+ pub struct LatestPriceRequestRepr {
20
+ // Either price feed ids or symbols must be specified.
20
21
pub price_feed_ids : Option < Vec < PriceFeedId > > ,
21
22
pub symbols : Option < Vec < String > > ,
22
23
pub properties : Vec < PriceFeedProperty > ,
@@ -32,9 +33,55 @@ pub struct LatestPriceRequest {
32
33
pub channel : Channel ,
33
34
}
34
35
36
+ #[ derive( Debug , Clone , PartialEq , Eq , Hash , Serialize ) ]
37
+ #[ serde( rename_all = "camelCase" ) ]
38
+ pub struct LatestPriceRequest ( LatestPriceRequestRepr ) ;
39
+
40
+ impl < ' de > Deserialize < ' de > for LatestPriceRequest {
41
+ fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
42
+ where
43
+ D : serde:: Deserializer < ' de > ,
44
+ {
45
+ let value = LatestPriceRequestRepr :: deserialize ( deserializer) ?;
46
+ Self :: new ( value) . map_err ( Error :: custom)
47
+ }
48
+ }
49
+
50
+ impl LatestPriceRequest {
51
+ pub fn new ( value : LatestPriceRequestRepr ) -> Result < Self , & ' static str > {
52
+ validate_price_feed_ids_or_symbols ( & value. price_feed_ids , & value. symbols ) ?;
53
+ validate_optional_nonempty_vec_has_unique_elements (
54
+ & value. price_feed_ids ,
55
+ "no price feed ids specified" ,
56
+ "duplicate price feed ids specified" ,
57
+ ) ?;
58
+ validate_optional_nonempty_vec_has_unique_elements (
59
+ & value. symbols ,
60
+ "no symbols specified" ,
61
+ "duplicate symbols specified" ,
62
+ ) ?;
63
+ validate_formats ( & value. formats ) ?;
64
+ validate_properties ( & value. properties ) ?;
65
+ Ok ( Self ( value) )
66
+ }
67
+ }
68
+
69
+ impl Deref for LatestPriceRequest {
70
+ type Target = LatestPriceRequestRepr ;
71
+
72
+ fn deref ( & self ) -> & Self :: Target {
73
+ & self . 0
74
+ }
75
+ }
76
+ impl DerefMut for LatestPriceRequest {
77
+ fn deref_mut ( & mut self ) -> & mut Self :: Target {
78
+ & mut self . 0
79
+ }
80
+ }
81
+
35
82
#[ derive( Debug , Clone , PartialEq , Eq , Hash , Serialize , Deserialize ) ]
36
83
#[ serde( rename_all = "camelCase" ) ]
37
- pub struct PriceRequest {
84
+ pub struct PriceRequestRepr {
38
85
pub timestamp : TimestampUs ,
39
86
// Either price feed ids or symbols must be specified.
40
87
pub price_feed_ids : Option < Vec < PriceFeedId > > ,
@@ -50,6 +97,52 @@ pub struct PriceRequest {
50
97
pub channel : Channel ,
51
98
}
52
99
100
+ #[ derive( Debug , Clone , PartialEq , Eq , Hash , Serialize ) ]
101
+ #[ serde( rename_all = "camelCase" ) ]
102
+ pub struct PriceRequest ( PriceRequestRepr ) ;
103
+
104
+ impl < ' de > Deserialize < ' de > for PriceRequest {
105
+ fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
106
+ where
107
+ D : serde:: Deserializer < ' de > ,
108
+ {
109
+ let value = PriceRequestRepr :: deserialize ( deserializer) ?;
110
+ Self :: new ( value) . map_err ( Error :: custom)
111
+ }
112
+ }
113
+
114
+ impl PriceRequest {
115
+ pub fn new ( value : PriceRequestRepr ) -> Result < Self , & ' static str > {
116
+ validate_price_feed_ids_or_symbols ( & value. price_feed_ids , & value. symbols ) ?;
117
+ validate_optional_nonempty_vec_has_unique_elements (
118
+ & value. price_feed_ids ,
119
+ "no price feed ids specified" ,
120
+ "duplicate price feed ids specified" ,
121
+ ) ?;
122
+ validate_optional_nonempty_vec_has_unique_elements (
123
+ & value. symbols ,
124
+ "no symbols specified" ,
125
+ "duplicate symbols specified" ,
126
+ ) ?;
127
+ validate_formats ( & value. formats ) ?;
128
+ validate_properties ( & value. properties ) ?;
129
+ Ok ( Self ( value) )
130
+ }
131
+ }
132
+
133
+ impl Deref for PriceRequest {
134
+ type Target = PriceRequestRepr ;
135
+
136
+ fn deref ( & self ) -> & Self :: Target {
137
+ & self . 0
138
+ }
139
+ }
140
+ impl DerefMut for PriceRequest {
141
+ fn deref_mut ( & mut self ) -> & mut Self :: Target {
142
+ & mut self . 0
143
+ }
144
+ }
145
+
53
146
#[ derive( Debug , Clone , PartialEq , Eq , Hash , Serialize , Deserialize ) ]
54
147
#[ serde( rename_all = "camelCase" ) ]
55
148
pub struct ReducePriceRequest {
@@ -221,40 +314,19 @@ impl<'de> Deserialize<'de> for SubscriptionParams {
221
314
222
315
impl SubscriptionParams {
223
316
pub fn new ( value : SubscriptionParamsRepr ) -> Result < Self , & ' static str > {
224
- if value. price_feed_ids . is_none ( ) && value. symbols . is_none ( ) {
225
- return Err ( "either price feed ids or symbols must be specified" ) ;
226
- }
227
- if value. price_feed_ids . is_some ( ) && value. symbols . is_some ( ) {
228
- return Err ( "either price feed ids or symbols must be specified, not both" ) ;
229
- }
230
-
231
- if let Some ( ref ids) = value. price_feed_ids {
232
- if ids. is_empty ( ) {
233
- return Err ( "no price feed ids specified" ) ;
234
- }
235
- if !ids. iter ( ) . all_unique ( ) {
236
- return Err ( "duplicate price feed ids specified" ) ;
237
- }
238
- }
239
-
240
- if let Some ( ref symbols) = value. symbols {
241
- if symbols. is_empty ( ) {
242
- return Err ( "no symbols specified" ) ;
243
- }
244
- if !symbols. iter ( ) . all_unique ( ) {
245
- return Err ( "duplicate symbols specified" ) ;
246
- }
247
- }
248
-
249
- if !value. formats . iter ( ) . all_unique ( ) {
250
- return Err ( "duplicate formats or chains specified" ) ;
251
- }
252
- if value. properties . is_empty ( ) {
253
- return Err ( "no properties specified" ) ;
254
- }
255
- if !value. properties . iter ( ) . all_unique ( ) {
256
- return Err ( "duplicate properties specified" ) ;
257
- }
317
+ validate_price_feed_ids_or_symbols ( & value. price_feed_ids , & value. symbols ) ?;
318
+ validate_optional_nonempty_vec_has_unique_elements (
319
+ & value. price_feed_ids ,
320
+ "no price feed ids specified" ,
321
+ "duplicate price feed ids specified" ,
322
+ ) ?;
323
+ validate_optional_nonempty_vec_has_unique_elements (
324
+ & value. symbols ,
325
+ "no symbols specified" ,
326
+ "duplicate symbols specified" ,
327
+ ) ?;
328
+ validate_formats ( & value. formats ) ?;
329
+ validate_properties ( & value. properties ) ?;
258
330
Ok ( Self ( value) )
259
331
}
260
332
}
@@ -467,6 +539,7 @@ pub struct SubscribedResponse {
467
539
#[ serde( rename_all = "camelCase" ) ]
468
540
pub struct InvalidFeedSubscriptionDetails {
469
541
pub unknown_ids : Vec < PriceFeedId > ,
542
+ pub unknown_symbols : Vec < String > ,
470
543
pub unsupported_channels : Vec < PriceFeedId > ,
471
544
pub unstable : Vec < PriceFeedId > ,
472
545
}
@@ -511,3 +584,53 @@ pub struct StreamUpdatedResponse {
511
584
#[ serde( flatten) ]
512
585
pub payload : JsonUpdate ,
513
586
}
587
+
588
+ // Common validation functions
589
+ fn validate_price_feed_ids_or_symbols (
590
+ price_feed_ids : & Option < Vec < PriceFeedId > > ,
591
+ symbols : & Option < Vec < String > > ,
592
+ ) -> Result < ( ) , & ' static str > {
593
+ if price_feed_ids. is_none ( ) && symbols. is_none ( ) {
594
+ return Err ( "either price feed ids or symbols must be specified" ) ;
595
+ }
596
+ if price_feed_ids. is_some ( ) && symbols. is_some ( ) {
597
+ return Err ( "either price feed ids or symbols must be specified, not both" ) ;
598
+ }
599
+ Ok ( ( ) )
600
+ }
601
+
602
+ fn validate_optional_nonempty_vec_has_unique_elements < T > (
603
+ vec : & Option < Vec < T > > ,
604
+ empty_msg : & ' static str ,
605
+ duplicate_msg : & ' static str ,
606
+ ) -> Result < ( ) , & ' static str >
607
+ where
608
+ T : Eq + std:: hash:: Hash ,
609
+ {
610
+ if let Some ( ref items) = vec {
611
+ if items. is_empty ( ) {
612
+ return Err ( empty_msg) ;
613
+ }
614
+ if !items. iter ( ) . all_unique ( ) {
615
+ return Err ( duplicate_msg) ;
616
+ }
617
+ }
618
+ Ok ( ( ) )
619
+ }
620
+
621
+ fn validate_properties ( properties : & [ PriceFeedProperty ] ) -> Result < ( ) , & ' static str > {
622
+ if properties. is_empty ( ) {
623
+ return Err ( "no properties specified" ) ;
624
+ }
625
+ if !properties. iter ( ) . all_unique ( ) {
626
+ return Err ( "duplicate properties specified" ) ;
627
+ }
628
+ Ok ( ( ) )
629
+ }
630
+
631
+ fn validate_formats ( formats : & [ Format ] ) -> Result < ( ) , & ' static str > {
632
+ if !formats. iter ( ) . all_unique ( ) {
633
+ return Err ( "duplicate formats or chains specified" ) ;
634
+ }
635
+ Ok ( ( ) )
636
+ }
0 commit comments