@@ -31,7 +31,7 @@ pub struct Request {
3131 ///
3232 /// This field is generated by deserializing to a [`RawValue`] and then
3333 /// calculating the offset of the backing slice within the `bytes` field.
34- id : Range < usize > ,
34+ id : Option < Range < usize > > ,
3535 /// A range of the `bytes` field that represents the method field of the
3636 /// JSON-RPC request.
3737 ///
@@ -49,7 +49,7 @@ pub struct Request {
4949 ///
5050 /// This field is generated by deserializing to a [`RawValue`] and then
5151 /// calculating the offset of the backing slice within the `bytes` field.
52- params : Range < usize > ,
52+ params : Option < Range < usize > > ,
5353}
5454
5555impl core:: fmt:: Debug for Request {
@@ -67,11 +67,11 @@ impl core::fmt::Debug for Request {
6767#[ derive( serde:: Deserialize ) ]
6868struct DeserHelper < ' a > {
6969 #[ serde( borrow) ]
70- id : & ' a RawValue ,
70+ id : Option < & ' a RawValue > ,
7171 #[ serde( borrow) ]
7272 method : & ' a RawValue ,
7373 #[ serde( borrow) ]
74- params : & ' a RawValue ,
74+ params : Option < & ' a RawValue > ,
7575}
7676
7777impl TryFrom < Bytes > for Request {
@@ -80,12 +80,19 @@ impl TryFrom<Bytes> for Request {
8080 fn try_from ( bytes : Bytes ) -> Result < Self , Self :: Error > {
8181 let DeserHelper { id, method, params } = serde_json:: from_slice ( bytes. as_ref ( ) ) ?;
8282
83- let id = find_range ! ( bytes, id. get( ) ) ;
84- // Ensure the id is not too long
85- let id_len = id. end - id. start ;
86- if id_len > ID_LEN_LIMIT {
87- return Err ( RequestError :: IdTooLarge ( id_len) ) ;
88- }
83+ let id = if let Some ( id) = id {
84+ let id = find_range ! ( bytes, id. get( ) ) ;
85+
86+ // Ensure the id is not too long
87+ let id_len = id. end - id. start ;
88+ if id_len > ID_LEN_LIMIT {
89+ return Err ( RequestError :: IdTooLarge ( id_len) ) ;
90+ }
91+
92+ Some ( id)
93+ } else {
94+ None
95+ } ;
8996
9097 // Ensure method is a string, and not too long, and trim the quotes
9198 // from it
@@ -101,7 +108,7 @@ impl TryFrom<Bytes> for Request {
101108 return Err ( RequestError :: MethodTooLarge ( method_len) ) ;
102109 }
103110
104- let params = find_range ! ( bytes, params. get( ) ) ;
111+ let params = params . map ( |params| find_range ! ( bytes, params. get( ) ) ) ;
105112
106113 Ok ( Self {
107114 bytes,
@@ -122,11 +129,20 @@ impl TryFrom<tokio_tungstenite::tungstenite::Utf8Bytes> for Request {
122129}
123130
124131impl Request {
125- /// Return a reference to the serialized ID field.
132+ /// Return a reference to the serialized ID field. If the ID field is
133+ /// missing, this will return `"null"`, ensuring that response correctly
134+ /// have a null ID, as per [the JSON-RPC spec].
135+ ///
136+ /// [the JSON-RPC spec]: https://www.jsonrpc.org/specification#response_object
126137 pub fn id ( & self ) -> & str {
127- // SAFETY: `id` is guaranteed to be valid JSON,
128- // and a valid slice of `bytes`.
129- unsafe { core:: str:: from_utf8_unchecked ( self . bytes . get_unchecked ( self . id . clone ( ) ) ) }
138+ self . id
139+ . as_ref ( )
140+ . map ( |range| {
141+ // SAFETY: `range` is guaranteed to be valid JSON, and a valid
142+ // slice of `bytes`.
143+ unsafe { core:: str:: from_utf8_unchecked ( self . bytes . get_unchecked ( range. clone ( ) ) ) }
144+ } )
145+ . unwrap_or ( "null" )
130146 }
131147
132148 /// Return an owned version of the serialized ID field.
@@ -161,9 +177,13 @@ impl Request {
161177
162178 /// Return a reference to the serialized params field.
163179 pub fn params ( & self ) -> & str {
164- // SAFETY: `params` is guaranteed to be valid JSON,
165- // and a valid slice of `bytes`.
166- unsafe { core:: str:: from_utf8_unchecked ( self . bytes . get_unchecked ( self . params . clone ( ) ) ) }
180+ if let Some ( range) = & self . params {
181+ // SAFETY: `range` is guaranteed to be valid JSON, and a valid
182+ // slice of `bytes`.
183+ unsafe { core:: str:: from_utf8_unchecked ( self . bytes . get_unchecked ( range. clone ( ) ) ) }
184+ } else {
185+ "null"
186+ }
167187 }
168188
169189 /// Deserialize the params field into a type.
0 commit comments