11use std:: collections:: hash_map:: Entry ;
2- use std:: collections:: { BTreeSet , HashMap , HashSet } ;
2+ use std:: collections:: { HashMap , HashSet } ;
33
44use askama:: Template ;
55use xdr_parser:: ast:: {
6- CfgExpr , Const , Definition , Enum , Struct , StructMember , Type , Typedef , Union , UnionArm ,
7- XdrSpec ,
6+ CfgExpr , Const , Definition , Enum , Struct , StructMember , Type , Typedef , Union , UnionArm , XdrSpec ,
87} ;
98use xdr_parser:: lexer:: IntBase ;
109use xdr_parser:: types:: { is_builtin_type, is_fixed_array, is_fixed_opaque, is_var_array, TypeInfo } ;
@@ -60,7 +59,7 @@ impl RustGenerator {
6059 let borrow = self
6160 . def_borrow
6261 . get ( & ( name. to_string ( ) , cfg. map ( ToString :: to_string) ) )
63- . cloned ( )
62+ . copied ( )
6463 . unwrap_or ( BorrowCfg :: Never ) ;
6564 view_emit ( self . view_required . contains ( name) , & borrow, cfg)
6665 }
@@ -308,8 +307,6 @@ impl RustGenerator {
308307 member_names,
309308 emit_view : r. emit_view ,
310309 view_cfg : r. view_cfg ,
311- emit_view_alias : r. emit_view_alias ,
312- view_alias_cfg : r. view_alias_cfg ,
313310 cfg,
314311 }
315312 }
@@ -396,8 +393,6 @@ impl RustGenerator {
396393 arms,
397394 emit_view : r. emit_view ,
398395 view_cfg : r. view_cfg ,
399- emit_view_alias : r. emit_view_alias ,
400- view_alias_cfg : r. view_alias_cfg ,
401396 cfg,
402397 default_arm_cfg,
403398 }
@@ -458,8 +453,6 @@ impl RustGenerator {
458453 custom_schemars : is_fixed_opaque_type && !custom_str && !no_display_fromstr,
459454 emit_view : r. emit_view ,
460455 view_cfg : r. view_cfg ,
461- emit_view_alias : r. emit_view_alias ,
462- view_alias_cfg : r. view_alias_cfg ,
463456 view_type_ref : resolved. view_type_ref ,
464457 from_view_expr : resolved. from_view_expr ,
465458 cfg,
@@ -556,69 +549,45 @@ impl RustGenerator {
556549 }
557550}
558551
559- /// Combine a definition's cfg with an additional condition, rendered as the
560- /// inside of a `#[cfg(...)]`.
561- fn combine_cfg ( def_cfg : Option < & str > , extra : & str ) -> String {
562- match def_cfg {
563- Some ( def) => format ! ( "all({def}, {extra})" ) ,
564- None => extra. to_string ( ) ,
565- }
566- }
567-
568552// =============================================================================
569553// Borrow analysis
570554// =============================================================================
571555
572- /// The cfg condition under which a type's `View` form actually borrows, i.e.
573- /// under which its `'a` lifetime is used .
556+ /// Whether a type holds heap-allocated data, and so whether its `View` form
557+ /// would use its `'a` lifetime.
574558///
575- /// A `View` type may borrow unconditionally, never, or only under some cfgs —
576- /// when the heap-allocated data it holds sits behind a cfg-gated union arm, or
577- /// is reached through a type that itself only holds heap data under a cfg.
578- #[ derive( Clone , Debug , PartialEq , Eq ) ]
559+ /// The distinction that matters is unconditional: only a type that borrows
560+ /// under every cfg gets a `View` form. One that borrows under some cfgs would
561+ /// need a cfg-gated `View`, which any unconditional container of it would name
562+ /// unconditionally and so reference where it does not exist.
563+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
579564enum BorrowCfg {
580- /// Holds no heap-allocated data under any cfg, so it needs no `View` form .
565+ /// Holds no heap-allocated data under any cfg.
581566 Never ,
582- /// Always borrows, so its `View` form is unconditional .
567+ /// Holds heap-allocated data under every cfg .
583568 Always ,
584- /// Borrows under the disjunction of these cfg predicates.
585- When ( BTreeSet < String > ) ,
569+ /// Holds heap-allocated data only under some cfgs, because it sits behind a
570+ /// cfg-gated union arm or is reached through a type that does.
571+ Sometimes ,
586572}
587573
588574impl BorrowCfg {
589575 fn or ( self , other : BorrowCfg ) -> BorrowCfg {
590576 match ( self , other) {
591577 ( BorrowCfg :: Always , _) | ( _, BorrowCfg :: Always ) => BorrowCfg :: Always ,
592578 ( BorrowCfg :: Never , o) | ( o, BorrowCfg :: Never ) => o,
593- ( BorrowCfg :: When ( mut a) , BorrowCfg :: When ( b) ) => {
594- a. extend ( b) ;
595- BorrowCfg :: When ( a)
596- }
579+ ( BorrowCfg :: Sometimes , BorrowCfg :: Sometimes ) => BorrowCfg :: Sometimes ,
597580 }
598581 }
599582
600583 /// Restrict to also require `cfg`, as for a cfg-gated union arm.
601584 fn and_cfg ( self , cfg : Option < & str > ) -> BorrowCfg {
602- let Some ( cfg) = cfg else { return self } ;
603- match self {
604- BorrowCfg :: Never => BorrowCfg :: Never ,
605- BorrowCfg :: Always => BorrowCfg :: When ( core:: iter:: once ( cfg. to_string ( ) ) . collect ( ) ) ,
606- BorrowCfg :: When ( set) => {
607- BorrowCfg :: When ( set. iter ( ) . map ( |e| format ! ( "all({cfg}, {e})" ) ) . collect ( ) )
608- }
585+ if cfg. is_none ( ) {
586+ return self ;
609587 }
610- }
611-
612- /// The cfg predicate to gate the borrowing `View` form on, or `None` when it
613- /// is unconditional.
614- fn render ( & self ) -> Option < String > {
615588 match self {
616- BorrowCfg :: Never | BorrowCfg :: Always => None ,
617- BorrowCfg :: When ( set) if set. len ( ) == 1 => set. iter ( ) . next ( ) . cloned ( ) ,
618- BorrowCfg :: When ( set) => Some ( format ! (
619- "any({})" ,
620- set. iter( ) . cloned( ) . collect:: <Vec <_>>( ) . join( ", " )
621- ) ) ,
589+ BorrowCfg :: Never => BorrowCfg :: Never ,
590+ BorrowCfg :: Always | BorrowCfg :: Sometimes => BorrowCfg :: Sometimes ,
622591 }
623592 }
624593}
@@ -653,11 +622,17 @@ impl<'a> BorrowAnalysis<'a> {
653622 analysis
654623 }
655624
656- /// The names that have a `View` form at all, i.e. that borrow under some cfg.
625+ /// The names that get a `View` form, i.e. that borrow under every cfg.
626+ ///
627+ /// A name that only borrows under some cfgs is excluded. Its `View` form
628+ /// would have to be cfg-gated, and an always-borrowing type containing it
629+ /// names that form unconditionally, so the reference would dangle wherever
630+ /// the cfg is off. Excluding it leaves containers holding the owned type in
631+ /// that position, which is correct under every cfg.
657632 fn view_required ( & self ) -> HashSet < String > {
658633 self . by_name
659634 . iter ( )
660- . filter ( |( _, b) | * * b != BorrowCfg :: Never )
635+ . filter ( |( _, b) | * * b == BorrowCfg :: Always )
661636 . map ( |( n, _) | n. clone ( ) )
662637 . collect ( )
663638 }
@@ -670,7 +645,7 @@ impl<'a> BorrowAnalysis<'a> {
670645 /// cycle always borrows.
671646 fn of_name ( & mut self , name : & str ) -> BorrowCfg {
672647 if let Some ( b) = self . by_name . get ( name) {
673- return b . clone ( ) ;
648+ return * b ;
674649 }
675650 if self . stack . contains ( name) {
676651 return BorrowCfg :: Always ;
@@ -685,7 +660,7 @@ impl<'a> BorrowAnalysis<'a> {
685660 borrow = borrow. or ( self . of_def ( def) . and_cfg ( def_cfg. as_deref ( ) ) ) ;
686661 }
687662 self . stack . remove ( name) ;
688- self . by_name . insert ( name. to_string ( ) , borrow. clone ( ) ) ;
663+ self . by_name . insert ( name. to_string ( ) , borrow) ;
689664 borrow
690665 }
691666
@@ -736,15 +711,12 @@ impl<'a> BorrowAnalysis<'a> {
736711
737712/// How a definition's borrowing `View` form is emitted.
738713///
739- /// Where the definition borrows, a real `{name}View<'a>` is emitted, so its `'a`
740- /// is always used. Where it does not, `{name}View<'a>` is emitted as a
741- /// transparent alias of the owned type, so types containing it can name it
742- /// uniformly across cfgs instead of being cfg-split themselves.
714+ /// A `{name}View<'a>` is emitted only where the definition borrows, so its `'a`
715+ /// is always used. Where it does not borrow, nothing is emitted: the owned type
716+ /// is already the whole value, and a heap-free type has nothing to borrow.
743717struct ViewEmit {
744718 emit_view : bool ,
745719 view_cfg : Option < String > ,
746- emit_view_alias : bool ,
747- view_alias_cfg : Option < String > ,
748720}
749721
750722/// Decide how to emit the `View` form of one definition.
@@ -755,32 +727,18 @@ fn view_emit(has_view: bool, borrow: &BorrowCfg, def_cfg: Option<&str>) -> ViewE
755727 let mut emit = ViewEmit {
756728 emit_view : false ,
757729 view_cfg : None ,
758- emit_view_alias : false ,
759- view_alias_cfg : None ,
760730 } ;
761731 if !has_view {
762732 return emit;
763733 }
764734 match borrow {
765- // The name has a View form only because another cfg branch of it
766- // borrows, so this definition contributes just the alias.
767- BorrowCfg :: Never => {
768- emit. emit_view_alias = true ;
769- emit. view_alias_cfg = def_cfg. map ( ToString :: to_string) ;
770- }
735+ // Nothing to borrow in this branch, or nothing to borrow under some
736+ // cfg. Either way this definition emits no View form.
737+ BorrowCfg :: Never | BorrowCfg :: Sometimes => { }
771738 BorrowCfg :: Always => {
772739 emit. emit_view = true ;
773740 emit. view_cfg = def_cfg. map ( ToString :: to_string) ;
774741 }
775- BorrowCfg :: When ( _) => {
776- let when = borrow
777- . render ( )
778- . expect ( "BorrowCfg::When always renders a predicate" ) ;
779- emit. emit_view = true ;
780- emit. view_cfg = Some ( combine_cfg ( def_cfg, & when) ) ;
781- emit. emit_view_alias = true ;
782- emit. view_alias_cfg = Some ( combine_cfg ( def_cfg, & format ! ( "not({when})" ) ) ) ;
783- }
784742 }
785743 emit
786744}
0 commit comments