1515
1616use std:: { collections:: HashMap , fmt, slice, str:: FromStr } ;
1717
18- use serde:: Serialize ;
19-
20- pub const NATS_LAST_STREAM : & str = "Nats-Last-Stream" ;
21- pub const NATS_LAST_CONSUMER : & str = "Nats-Last-Consumer" ;
22-
23- /// Direct Get headers
24- pub const NATS_STREAM : & str = "Nats-Stream" ;
25- pub const NATS_SEQUENCE : & str = "Nats-Sequence" ;
26- pub const NATS_TIME_STAMP : & str = "Nats-Time-Stamp" ;
27- pub const NATS_SUBJECT : & str = "Nats-Subject" ;
28- pub const NATS_LAST_SEQUENCE : & str = "Nats-Last-Sequence" ;
29-
30- /// Nats-Expected-Last-Subject-Sequence
31- pub const NATS_EXPECTED_LAST_SUBJECT_SEQUENCE : & str = "Nats-Expected-Last-Subject-Sequence" ;
32- /// Message identifier used for deduplication window
33- pub const NATS_MESSAGE_ID : & str = "Nats-Msg-Id" ;
34- /// Last expected message ID for JetStream message publish
35- pub const NATS_EXPECTED_LAST_MESSAGE_ID : & str = "Nats-Expected-Last-Msg-Id" ;
36- /// Last expected sequence for JetStream message publish
37- pub const NATS_EXPECTED_LAST_SEQUENCE : & str = "Nats-Expected-Last-Sequence" ;
38- /// Expect that given message will be ingested by specified stream.
39- pub const NATS_EXPECTED_STREAM : & str = "Nats-Expected-Stream" ;
40-
4118/// A struct for handling NATS headers.
4219/// Has a similar API to [http::header], but properly serializes and deserializes
4320/// according to NATS requirements.
@@ -56,7 +33,7 @@ pub const NATS_EXPECTED_STREAM: &str = "Nats-Expected-Stream";
5633/// # Ok(())
5734/// # }
5835/// ```
59- #[ derive( Clone , PartialEq , Eq , Debug , Serialize , Default ) ]
36+ #[ derive( Clone , PartialEq , Eq , Debug , Default ) ]
6037pub struct HeaderMap {
6138 inner : HashMap < HeaderName , HeaderValue > ,
6239}
@@ -154,7 +131,7 @@ impl HeaderMap {
154131 buf. extend_from_slice ( b"NATS/1.0\r \n " ) ;
155132 for ( k, vs) in & self . inner {
156133 for v in vs. iter ( ) {
157- buf. extend_from_slice ( k. value . as_bytes ( ) ) ;
134+ buf. extend_from_slice ( k. as_str ( ) . as_bytes ( ) ) ;
158135 buf. extend_from_slice ( b": " ) ;
159136 buf. extend_from_slice ( v. as_bytes ( ) ) ;
160137 buf. extend_from_slice ( b"\r \n " ) ;
@@ -179,7 +156,7 @@ impl HeaderMap {
179156/// # Ok(())
180157/// # }
181158/// ```
182- #[ derive( Clone , PartialEq , Eq , Debug , Serialize , Default ) ]
159+ #[ derive( Clone , PartialEq , Eq , Debug , Default ) ]
183160pub struct HeaderValue {
184161 value : Vec < String > ,
185162}
@@ -288,7 +265,7 @@ pub trait IntoHeaderName {
288265impl IntoHeaderName for & str {
289266 fn into_header_name ( self ) -> HeaderName {
290267 HeaderName {
291- value : self . to_string ( ) ,
268+ inner : HeaderRepr :: Custom ( self . to_string ( ) ) ,
292269 }
293270 }
294271}
@@ -316,10 +293,120 @@ impl IntoHeaderValue for HeaderValue {
316293 }
317294}
318295
319- #[ derive( Clone , PartialEq , Eq , Hash , Debug , Serialize ) ]
296+ macro_rules! standard_headers {
297+ (
298+ $(
299+ $( #[ $docs: meta] ) *
300+ ( $variant: ident, $constant: ident, $bytes: literal) ;
301+ ) +
302+ ) => {
303+ #[ allow( clippy:: enum_variant_names) ]
304+ #[ derive( Debug , Clone , Copy , Eq , PartialEq , Hash ) ]
305+ enum StandardHeader {
306+ $(
307+ $variant,
308+ ) +
309+ }
310+
311+ $(
312+ $( #[ $docs] ) *
313+ pub const $constant: HeaderName = HeaderName {
314+ inner: HeaderRepr :: Standard ( StandardHeader :: $variant) ,
315+ } ;
316+ ) +
317+
318+ impl StandardHeader {
319+ #[ inline]
320+ fn as_str( & self ) -> & ' static str {
321+ match * self {
322+ $(
323+ StandardHeader :: $variant => unsafe { std:: str :: from_utf8_unchecked( $bytes ) } ,
324+ ) +
325+ }
326+ }
327+
328+ const fn from_bytes( bytes: & [ u8 ] ) -> Option <StandardHeader > {
329+ match bytes {
330+ $(
331+ $bytes => Some ( StandardHeader :: $variant) ,
332+ ) +
333+ _ => None ,
334+ }
335+ }
336+ }
337+
338+ #[ cfg( test) ]
339+ mod standard_header_tests {
340+ use super :: HeaderName ;
341+ use std:: str :: { self , FromStr } ;
342+
343+ const TEST_HEADERS : & ' static [ ( & ' static HeaderName , & ' static [ u8 ] ) ] = & [
344+ $(
345+ ( & super :: $constant, $bytes) ,
346+ ) +
347+ ] ;
348+
349+ #[ test]
350+ fn from_str( ) {
351+ for & ( header, bytes) in TEST_HEADERS {
352+ let utf8 = str :: from_utf8( bytes) . expect( "string constants isn't utf8" ) ;
353+ assert_eq!( HeaderName :: from_str( utf8) . unwrap( ) , * header) ;
354+ }
355+ }
356+ }
357+ }
358+ }
359+
360+ // Generate constants for all standard NATS headers.
361+ standard_headers ! {
362+ /// The name of the stream the message belongs to.
363+ ( NatsStream , NATS_STREAM , b"Nats-Stream" ) ;
364+ /// The sequence number of the message within the stream.
365+ ( NatsSequence , NATS_SEQUENCE , b"Nats-Sequence" ) ;
366+ /// The timestamp of when the message was sent.
367+ ( NatsTimeStamp , NATS_TIME_STAMP , b"Nats-Time-Stamp" ) ;
368+ /// The subject of the message, used for routing and filtering messages.
369+ ( NatsSubject , NATS_SUBJECT , b"Nats-Subject" ) ;
370+ /// A unique identifier for the message.
371+ ( NatsMessageId , NATS_MESSAGE_ID , b"Nats-Msg-Id" ) ;
372+ /// The last known stream the message was part of.
373+ ( NatsLastStream , NATS_LAST_STREAM , b"Nats-Last-Stream" ) ;
374+ /// The last known consumer that processed the message.
375+ ( NatsLastConsumer , NATS_LAST_CONSUMER , b"Nats-Last-Consumer" ) ;
376+ /// The last known sequence number of the message.
377+ ( NatsLastSequence , NATS_LAST_SEQUENCE , b"Nats-Last-Sequence" ) ;
378+ /// The expected last sequence number of the subject.
379+ ( NatsExpectgedLastSubjectSequence , NATS_EXPECTED_LAST_SUBJECT_SEQUENCE , b"Nats-Expected-Last-Subject-Sequence" ) ;
380+ /// The expected last message ID within the stream.
381+ ( NatsExpectedLastMessageId , NATS_EXPECTED_LAST_MESSAGE_ID , b"Nats-Expected-Last-Msg-Id" ) ;
382+ /// The expected last sequence number within the stream.
383+ ( NatsExpectedLastSequence , NATS_EXPECTED_LAST_SEQUENCE , b"Nats-Expected-Last-Sequence" ) ;
384+ /// The expected stream the message should be part of.
385+ ( NatsExpectedStream , NATS_EXPECTED_STREAM , b"Nats-Expected-Stream" ) ;
386+ }
387+
388+ #[ derive( Debug , Hash , PartialEq , Eq , Clone ) ]
389+ enum HeaderRepr {
390+ Standard ( StandardHeader ) ,
391+ Custom ( String ) ,
392+ }
393+
394+ #[ derive( Clone , PartialEq , Eq , Hash , Debug ) ]
320395pub struct HeaderName {
321- value : String ,
396+ inner : HeaderRepr ,
322397}
398+
399+ impl HeaderName {
400+ /// Returns a `str` representation of the header.
401+ #[ inline]
402+ fn as_str ( & self ) -> & str {
403+ match self . inner {
404+ HeaderRepr :: Standard ( v) => v. as_str ( ) ,
405+ HeaderRepr :: Custom ( ref v) => v. as_str ( ) ,
406+ }
407+ }
408+ }
409+
323410impl FromStr for HeaderName {
324411 type Err = ParseHeaderNameError ;
325412
@@ -328,27 +415,32 @@ impl FromStr for HeaderName {
328415 return Err ( ParseHeaderNameError ) ;
329416 }
330417
331- Ok ( HeaderName {
332- value : s. to_string ( ) ,
333- } )
418+ match StandardHeader :: from_bytes ( s. as_ref ( ) ) {
419+ Some ( v) => Ok ( HeaderName {
420+ inner : HeaderRepr :: Standard ( v) ,
421+ } ) ,
422+ None => Ok ( HeaderName {
423+ inner : HeaderRepr :: Custom ( s. to_string ( ) ) ,
424+ } ) ,
425+ }
334426 }
335427}
336428
337429impl fmt:: Display for HeaderName {
338430 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
339- fmt:: Display :: fmt ( & self . value , f)
431+ fmt:: Display :: fmt ( & self . as_str ( ) , f)
340432 }
341433}
342434
343435impl AsRef < [ u8 ] > for HeaderName {
344436 fn as_ref ( & self ) -> & [ u8 ] {
345- self . value . as_bytes ( )
437+ self . as_str ( ) . as_bytes ( )
346438 }
347439}
348440
349441impl AsRef < str > for HeaderName {
350442 fn as_ref ( & self ) -> & str {
351- self . value . as_ref ( )
443+ self . as_str ( )
352444 }
353445}
354446
0 commit comments