@@ -118,8 +118,13 @@ impl Field {
118118 match self . kind {
119119 Kind :: Plain ( ref default) => {
120120 let default = default. typed ( ) ;
121+ let comparison = if matches ! ( self . ty, Ty :: String ( StringTy :: ArcStr ) ) {
122+ quote ! ( #ident. as_ref( ) != #default )
123+ } else {
124+ quote ! ( #ident != #default )
125+ } ;
121126 quote ! {
122- if #ident != # default {
127+ if #comparison {
123128 #encode_fn( #tag, & #ident, buf) ;
124129 }
125130 }
@@ -172,8 +177,13 @@ impl Field {
172177 match self . kind {
173178 Kind :: Plain ( ref default) => {
174179 let default = default. typed ( ) ;
180+ let comparison = if matches ! ( self . ty, Ty :: String ( StringTy :: ArcStr ) ) {
181+ quote ! ( #ident. as_ref( ) != #default )
182+ } else {
183+ quote ! ( #ident != #default )
184+ } ;
175185 quote ! {
176- if #ident != # default {
186+ if #comparison {
177187 #encoded_len_fn( #tag, & #ident)
178188 } else {
179189 0
@@ -194,7 +204,10 @@ impl Field {
194204 Kind :: Plain ( ref default) | Kind :: Required ( ref default) => {
195205 let default = default. typed ( ) ;
196206 match self . ty {
197- Ty :: String | Ty :: Bytes ( ..) => quote ! ( #ident. clear( ) ) ,
207+ Ty :: String ( StringTy :: ArcStr ) => {
208+ quote ! ( #ident = :: core:: default :: Default :: default ( ) )
209+ }
210+ Ty :: String ( ..) | Ty :: Bytes ( ..) => quote ! ( #ident. clear( ) ) ,
198211 _ => quote ! ( #ident = #default ) ,
199212 }
200213 }
@@ -206,7 +219,17 @@ impl Field {
206219 /// Returns an expression which evaluates to the default value of the field.
207220 pub fn default ( & self , prost_path : & Path ) -> TokenStream {
208221 match self . kind {
209- Kind :: Plain ( ref value) | Kind :: Required ( ref value) => value. owned ( prost_path) ,
222+ Kind :: Plain ( ref value) | Kind :: Required ( ref value) => {
223+ // Special handling for Arc<str> default value
224+ if matches ! ( self . ty, Ty :: String ( StringTy :: ArcStr ) ) {
225+ if matches ! ( value, DefaultValue :: String ( s) if s. is_empty( ) ) {
226+ return quote ! ( #prost_path:: alloc:: sync:: Arc :: from( "" ) ) ;
227+ } else if let DefaultValue :: String ( s) = value {
228+ return quote ! ( #prost_path:: alloc:: sync:: Arc :: from( #s) ) ;
229+ }
230+ }
231+ value. owned ( prost_path)
232+ }
210233 Kind :: Optional ( _) => quote ! ( :: core:: option:: Option :: None ) ,
211234 Kind :: Repeated | Kind :: Packed => quote ! ( #prost_path:: alloc:: vec:: Vec :: new( ) ) ,
212235 }
@@ -393,7 +416,7 @@ pub enum Ty {
393416 Sfixed32 ,
394417 Sfixed64 ,
395418 Bool ,
396- String ,
419+ String ( StringTy ) ,
397420 Bytes ( BytesTy ) ,
398421 Enumeration ( Path ) ,
399422}
@@ -404,6 +427,12 @@ pub enum BytesTy {
404427 Bytes ,
405428}
406429
430+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
431+ pub enum StringTy {
432+ String ,
433+ ArcStr ,
434+ }
435+
407436impl BytesTy {
408437 fn try_from_str ( s : & str ) -> Result < Self , Error > {
409438 match s {
@@ -421,6 +450,23 @@ impl BytesTy {
421450 }
422451}
423452
453+ impl StringTy {
454+ fn try_from_str ( s : & str ) -> Result < Self , Error > {
455+ match s {
456+ "string" => Ok ( StringTy :: String ) ,
457+ "arc_str" => Ok ( StringTy :: ArcStr ) ,
458+ _ => bail ! ( "Invalid string type: {}" , s) ,
459+ }
460+ }
461+
462+ fn rust_type ( & self , prost_path : & Path ) -> TokenStream {
463+ match self {
464+ StringTy :: String => quote ! { #prost_path:: alloc:: string:: String } ,
465+ StringTy :: ArcStr => quote ! { #prost_path:: alloc:: sync:: Arc <str > } ,
466+ }
467+ }
468+ }
469+
424470impl Ty {
425471 pub fn from_attr ( attr : & Meta ) -> Result < Option < Ty > , Error > {
426472 let ty = match * attr {
@@ -437,8 +483,17 @@ impl Ty {
437483 Meta :: Path ( ref name) if name. is_ident ( "sfixed32" ) => Ty :: Sfixed32 ,
438484 Meta :: Path ( ref name) if name. is_ident ( "sfixed64" ) => Ty :: Sfixed64 ,
439485 Meta :: Path ( ref name) if name. is_ident ( "bool" ) => Ty :: Bool ,
440- Meta :: Path ( ref name) if name. is_ident ( "string" ) => Ty :: String ,
486+ Meta :: Path ( ref name) if name. is_ident ( "string" ) => Ty :: String ( StringTy :: String ) ,
441487 Meta :: Path ( ref name) if name. is_ident ( "bytes" ) => Ty :: Bytes ( BytesTy :: Vec ) ,
488+ Meta :: NameValue ( MetaNameValue {
489+ ref path,
490+ value :
491+ Expr :: Lit ( ExprLit {
492+ lit : Lit :: Str ( ref l) ,
493+ ..
494+ } ) ,
495+ ..
496+ } ) if path. is_ident ( "string" ) => Ty :: String ( StringTy :: try_from_str ( & l. value ( ) ) ?) ,
442497 Meta :: NameValue ( MetaNameValue {
443498 ref path,
444499 value :
@@ -482,7 +537,7 @@ impl Ty {
482537 "sfixed32" => Ty :: Sfixed32 ,
483538 "sfixed64" => Ty :: Sfixed64 ,
484539 "bool" => Ty :: Bool ,
485- "string" => Ty :: String ,
540+ "string" => Ty :: String ( StringTy :: String ) ,
486541 "bytes" => Ty :: Bytes ( BytesTy :: Vec ) ,
487542 s if s. len ( ) > enumeration_len && & s[ ..enumeration_len] == "enumeration" => {
488543 let s = & s[ enumeration_len..] . trim ( ) ;
@@ -518,7 +573,7 @@ impl Ty {
518573 Ty :: Sfixed32 => "sfixed32" ,
519574 Ty :: Sfixed64 => "sfixed64" ,
520575 Ty :: Bool => "bool" ,
521- Ty :: String => "string" ,
576+ Ty :: String ( .. ) => "string" ,
522577 Ty :: Bytes ( ..) => "bytes" ,
523578 Ty :: Enumeration ( ..) => "enum" ,
524579 }
@@ -527,7 +582,7 @@ impl Ty {
527582 // TODO: rename to 'owned_type'.
528583 pub fn rust_type ( & self , prost_path : & Path ) -> TokenStream {
529584 match self {
530- Ty :: String => quote ! ( # prost_path:: alloc :: string :: String ) ,
585+ Ty :: String ( ty ) => ty . rust_type ( prost_path) ,
531586 Ty :: Bytes ( ty) => ty. rust_type ( prost_path) ,
532587 _ => self . rust_ref_type ( ) ,
533588 }
@@ -549,7 +604,7 @@ impl Ty {
549604 Ty :: Sfixed32 => quote ! ( i32 ) ,
550605 Ty :: Sfixed64 => quote ! ( i64 ) ,
551606 Ty :: Bool => quote ! ( bool ) ,
552- Ty :: String => quote ! ( & str ) ,
607+ Ty :: String ( .. ) => quote ! ( & str ) ,
553608 Ty :: Bytes ( ..) => quote ! ( & [ u8 ] ) ,
554609 Ty :: Enumeration ( ..) => quote ! ( i32 ) ,
555610 }
@@ -564,7 +619,7 @@ impl Ty {
564619
565620 /// Returns false if the scalar type is length delimited (i.e., `string` or `bytes`).
566621 pub fn is_numeric ( & self ) -> bool {
567- !matches ! ( self , Ty :: String | Ty :: Bytes ( ..) )
622+ !matches ! ( self , Ty :: String ( .. ) | Ty :: Bytes ( ..) )
568623 }
569624}
570625
@@ -660,7 +715,7 @@ impl DefaultValue {
660715 Lit :: Int ( ref lit) if * ty == Ty :: Double => DefaultValue :: F64 ( lit. base10_parse ( ) ?) ,
661716
662717 Lit :: Bool ( ref lit) if * ty == Ty :: Bool => DefaultValue :: Bool ( lit. value ) ,
663- Lit :: Str ( ref lit) if * ty == Ty :: String => DefaultValue :: String ( lit. value ( ) ) ,
718+ Lit :: Str ( ref lit) if matches ! ( * ty, Ty :: String ( .. ) ) => DefaultValue :: String ( lit. value ( ) ) ,
664719 Lit :: ByteStr ( ref lit)
665720 if * ty == Ty :: Bytes ( BytesTy :: Bytes ) || * ty == Ty :: Bytes ( BytesTy :: Vec ) =>
666721 {
@@ -769,7 +824,7 @@ impl DefaultValue {
769824 Ty :: Uint64 | Ty :: Fixed64 => DefaultValue :: U64 ( 0 ) ,
770825
771826 Ty :: Bool => DefaultValue :: Bool ( false ) ,
772- Ty :: String => DefaultValue :: String ( String :: new ( ) ) ,
827+ Ty :: String ( .. ) => DefaultValue :: String ( String :: new ( ) ) ,
773828 Ty :: Bytes ( ..) => DefaultValue :: Bytes ( Vec :: new ( ) ) ,
774829 Ty :: Enumeration ( ref path) => DefaultValue :: Enumeration ( quote ! ( #path:: default ( ) ) ) ,
775830 }
0 commit comments