Ignore:
Timestamp:
Mar 25, 2024, 9:02:18 AM (6 months ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
master
Children:
051aec4
Parents:
6a8c773
Message:

word smithing and poking at rust enumerations

File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/jiada_liang_MMath/relatedwork.tex

    r6a8c773 r41fb996  
    608608\lstnewenvironment{rust}[1][]{\lstset{language=Rust,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    609609
    610 Enumerations
     610Rust provides a scoped enumeration based on variant types.
     611% An enumeration, also referred to as an enum, is a simultaneous definition of a nominal enumerated type as well as a set of constructors, that can be used to create or pattern-match values of the corresponding enumerated type.
     612An enumeration without constructors is called field-less.
    611613\begin{rust}
    612         Syntax
    613         Enumeration :
    614            enum IDENTIFIER  GenericParams? WhereClause? { EnumItems? }
    615 
    616         EnumItems :
    617            EnumItem ( , EnumItem )* ,?
    618 
    619         EnumItem :
    620            OuterAttribute* Visibility?
    621            IDENTIFIER ( EnumItemTuple | EnumItemStruct )? EnumItemDiscriminant?
    622 
    623         EnumItemTuple :
    624            ( TupleFields? )
    625 
    626         EnumItemStruct :
    627            { StructFields? }
    628 
    629         EnumItemDiscriminant :
    630            = Expression
     614enum Week { Mon, Tues, Wed, Thu, Fri, Sat, Sun@,@ }
     615let mut week: Week = Week::Mon;
     616week = Week::Fri;
    631617\end{rust}
    632 An enumeration, also referred to as an enum, is a simultaneous definition of a nominal enumerated type as well as a set of constructors, that can be used to create or pattern-match values of the corresponding enumerated type.
    633 
    634 Enumerations are declared with the keyword enum.
    635 
    636 An example of an enum item and its use:
     618A field-less enumeration with only unit variants is called unit-only.
    637619\begin{rust}
    638 enum Animal {
    639         Dog,
    640         Cat,
    641 }
    642 
    643 let mut a: Animal = Animal::Dog;
    644 a = Animal::Cat;
     620enum Week { Mon = 0, Tues = 1, Wed = 2, Thu = 3, Fri = 4, Sat = 5, Sun = 6 }
    645621\end{rust}
    646622Enum constructors can have either named or unnamed fields:
    647623\begin{rust}
    648624enum Animal {
    649         Dog(String, f64),
    650         Cat { name: String, weight: f64 },
    651 }
    652 
     625        Dog( String, f64 ),
     626        Cat{ name: String, weight: f64 },
     627}
    653628let mut a: Animal = Animal::Dog("Cocoa".to_string(), 37.2);
    654629a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 };
    655630\end{rust}
    656 In this example, Cat is a struct-like enum variant, whereas Dog is simply called an enum variant.
    657 
    658 An enum where no constructors contain fields are called a field-less enum. For example, this is a fieldless enum:
     631Here, @Dog@ is an @enum@ variant, whereas @Cat@ is a struct-like variant.
     632
     633Each @enum@ type has an implicit integer tag (discriminant), with a unique value for each variant type.
     634Like a C enumeration, the tag values for the variant types start at 0 with auto incrementing.
     635The tag is re-purposed for enumeration by allowing it to be explicitly set, and auto incrmenting continues from that value.
     636\begin{cquote}
     637\sf\setlength{\tabcolsep}{3pt}
     638\begin{tabular}{rcccccccr}
     639@enum@ Week \{  & Mon,  & Tue,  & Wed = 2,      & Thu = 10,     & Fri,  & Sat = 5,      & Sun   & \};   \\
     640\rm tags                & 0             & 1             & 2                     & 10            & 11    & 5                     & 6             &               \\
     641\end{tabular}
     642\end{cquote}
     643In general, the tag can only be read as an opaque reference for comparison.
    659644\begin{rust}
    660 enum Fieldless {
    661         Tuple(),
    662         Struct{},
    663         Unit,
    664 }
     645if mem::discriminant(&week) == mem::discriminant(&Week::Mon) ...
    665646\end{rust}
    666 If a field-less enum only contains unit variants, the enum is called an unit-only enum. For example:
     647If the enumeration is unit-only, or field-less with no explicit discriminants and where only unit variants are explicit, then the discriminant is accessible with a numeric cast.
    667648\begin{rust}
    668 enum Enum {
    669         Foo = 3,
    670         Bar = 2,
    671         Baz = 1,
    672 }
    673 \end{rust}
    674 
    675 \subsection{Discriminants}
    676 
    677 Each enum instance has a discriminant: an integer logically associated to it that is used to determine which variant it holds.
    678 
    679 Under the default representation, the discriminant is interpreted as an isize value. However, the compiler is allowed to use a smaller type (or another means of distinguishing variants) in its actual memory layout.
    680 
    681 \subsection{Assigning discriminant values}
    682 
    683 \subsection{Explicit discriminants}
    684 
    685 In two circumstances, the discriminant of a variant may be explicitly set by following the variant name with = and a constant expression:
    686 
    687         if the enumeration is "unit-only".
    688 
    689         if a primitive representation is used. For example:
    690 \begin{rust}
    691         #[repr(u8)]
    692         enum Enum {
    693                 Unit = 3,
    694                 Tuple(u16),
    695                 Struct {
    696                         a: u8,
    697                         b: u16,
    698                 } = 1,
    699         }
    700 \end{rust}
    701 
    702 \subsection{Implicit discriminants}
    703 
    704 If a discriminant for a variant is not specified, then it is set to one higher than the discriminant of the previous variant in the declaration. If the discriminant of the first variant in the declaration is unspecified, then it is set to zero.
    705 \begin{rust}
    706 enum Foo {
    707         Bar,                    // 0
    708         Baz = 123,        // 123
    709         Quux,              // 124
    710 }
    711 
    712 let baz_discriminant = Foo::Baz as u32;
    713 assert_eq!(baz_discriminant, 123);
    714 \end{rust}
    715 
    716 \subsection{Restrictions}
    717 
    718 It is an error when two variants share the same discriminant.
    719 \begin{rust}
    720 enum SharedDiscriminantError {
    721         SharedA = 1,
    722         SharedB = 1
    723 }
    724 
    725 enum SharedDiscriminantError2 {
    726         Zero,      // 0
    727         One,            // 1
    728         OneToo = 1  // 1 (collision with previous!)
    729 }
    730 \end{rust}
    731 It is also an error to have an unspecified discriminant where the previous discriminant is the maximum value for the size of the discriminant.
    732 \begin{rust}
    733 #[repr(u8)]
    734 enum OverflowingDiscriminantError {
    735         Max = 255,
    736         MaxPlusOne // Would be 256, but that overflows the enum.
    737 }
    738 
    739 #[repr(u8)]
    740 enum OverflowingDiscriminantError2 {
    741         MaxMinusOne = 254, // 254
    742         Max,                       // 255
    743         MaxPlusOne               // Would be 256, but that overflows the enum.
    744 }
    745 \end{rust}
    746 
    747 \subsection{Accessing discriminant}
    748 
    749 \begin{rust}
    750 Via mem::discriminant
    751 \end{rust}
    752 @mem::discriminant@ returns an opaque reference to the discriminant of an enum value which can be compared. This cannot be used to get the value of the discriminant.
    753 
    754 \subsection{Casting}
    755 
    756 If an enumeration is unit-only (with no tuple and struct variants), then its discriminant can be directly accessed with a numeric cast; e.g.:
    757 \begin{rust}
    758 enum Enum {
    759         Foo,
    760         Bar,
    761         Baz,
    762 }
    763 
    764 assert_eq!(0, Enum::Foo as isize);
    765 assert_eq!(1, Enum::Bar as isize);
    766 assert_eq!(2, Enum::Baz as isize);
    767 \end{rust}
    768 Field-less enums can be casted if they do not have explicit discriminants, or where only unit variants are explicit.
    769 \begin{rust}
    770 enum Fieldless {
    771         Tuple(),
    772         Struct{},
    773         Unit,
    774 }
    775 
    776 assert_eq!(0, Fieldless::Tuple() as isize);
    777 assert_eq!(1, Fieldless::Struct{} as isize);
    778 assert_eq!(2, Fieldless::Unit as isize);
    779 \end{rust}
    780 \begin{rust}
    781 #[repr(u8)]
    782 enum FieldlessWithDiscrimants {
    783         First = 10,
    784         Tuple(),
    785         Second = 20,
    786         Struct{},
    787         Unit,
    788 }
    789 
    790 assert_eq!(10, FieldlessWithDiscrimants::First as u8);
    791 assert_eq!(11, FieldlessWithDiscrimants::Tuple() as u8);
    792 assert_eq!(20, FieldlessWithDiscrimants::Second as u8);
    793 assert_eq!(21, FieldlessWithDiscrimants::Struct{} as u8);
    794 assert_eq!(22, FieldlessWithDiscrimants::Unit as u8);
    795 \end{rust}
    796 
    797 \subsection{Pointer casting}
    798 
    799 If the enumeration specifies a primitive representation, then the discriminant may be reliably accessed via unsafe pointer casting:
    800 \begin{rust}
    801 #[repr(u8)]
    802 enum Enum {
    803         Unit,
    804         Tuple(bool),
    805         Struct{a: bool},
    806 }
    807 
    808 impl Enum {
    809         fn discriminant(&self) -> u8 {
    810                 unsafe { *(self as *const Self as *const u8) }
    811         }
    812 }
    813 
    814 let unit_like = Enum::Unit;
    815 let tuple_like = Enum::Tuple(true);
    816 let struct_like = Enum::Struct{a: false};
    817 
    818 assert_eq!(0, unit_like.discriminant());
    819 assert_eq!(1, tuple_like.discriminant());
    820 assert_eq!(2, struct_like.discriminant());
    821 \end{rust}
    822 
    823 \subsection{Zero-variant enums}
    824 
    825 Enums with zero variants are known as zero-variant enums. As they have no valid values, they cannot be instantiated.
    826 \begin{rust}
    827 enum ZeroVariants {}
    828 \end{rust}
    829 Zero-variant enums are equivalent to the never type, but they cannot be coerced into other types.
    830 \begin{rust}
    831 let x: ZeroVariants = panic!();
    832 let y: u32 = x; // mismatched type error
    833 \end{rust}
    834 
    835 \subsection{Variant visibility}
    836 
    837 Enum variants syntactically allow a Visibility annotation, but this is rejected when the enum is validated. This allows items to be parsed with a unified syntax across different contexts where they are used.
    838 \begin{rust}
    839 macro_rules! mac_variant {
    840         ($vis:vis $name:ident) => {
    841                 enum $name {
    842                         $vis Unit,
    843 
    844                         $vis Tuple(u8, u16),
    845 
    846                         $vis Struct { f: u8 },
    847                 }
    848         }
    849 }
    850 
    851 // Empty `vis` is allowed.
    852 mac_variant! { E }
    853 
    854 // This is allowed, since it is removed before being validated.
    855 #[cfg(FALSE)]
    856 enum E {
    857         pub U,
    858         pub(crate) T(u8),
    859         pub(super) T { f: String }
    860 }
     649if week as isize == Week::Mon as isize ...
    861650\end{rust}
    862651
Note: See TracChangeset for help on using the changeset viewer.