@@ -579,53 +579,99 @@ impl TryFrom<u8> for Encryption {
579579}
580580
581581/// Cipher mode of encryption algorithm.
582- #[ derive( Copy , Clone , Eq , PartialEq , Ord , PartialOrd , Hash , Debug ) ]
583- pub enum CipherMode {
582+ ///
583+ /// Values without an associated constant are either reserved for future
584+ /// PNA specification (raw value < 128) or application-specific private
585+ /// values (raw value >= 128).
586+ #[ derive( Copy , Clone , Eq , PartialEq , Ord , PartialOrd , Hash ) ]
587+ pub struct CipherMode ( u8 ) ;
588+
589+ impl CipherMode {
584590 /// Cipher Block Chaining mode.
585- CBC ,
591+ pub const CBC : Self = Self ( 0 ) ;
586592 /// Counter mode.
587- CTR ,
588- /// Value reserved for future PNA specification (raw value < 128).
589- Reserved ( u8 ) ,
590- /// Application-specific private value (raw value >= 128).
591- Private ( u8 ) ,
592- }
593+ pub const CTR : Self = Self ( 1 ) ;
593594
594- impl CipherMode {
595- /// Serialize this cipher mode to its u8 representation.
595+ /// Deserializes a cipher mode from its u8 representation.
596+ ///
597+ /// Every byte value is a valid cipher mode value, so this conversion
598+ /// never fails.
599+ #[ inline]
600+ pub const fn from_byte ( value : u8 ) -> Self {
601+ Self ( value)
602+ }
603+
604+ /// Serializes this cipher mode to its u8 representation.
596605 #[ inline]
597606 pub const fn to_byte ( self ) -> u8 {
598- match self {
599- Self :: CBC => 0 ,
600- Self :: CTR => 1 ,
601- Self :: Reserved ( v) | Self :: Private ( v) => v,
607+ self . 0
608+ }
609+
610+ /// Creates an application-specific private value.
611+ ///
612+ /// Returns `Some` if `value` is in the private range (`128..=255`),
613+ /// otherwise `None`.
614+ #[ inline]
615+ pub const fn new_private ( value : u8 ) -> Option < Self > {
616+ if value >= 128 {
617+ Some ( Self ( value) )
618+ } else {
619+ None
602620 }
603621 }
604622
605- /// Returns `true` if this is a reserved value.
623+ /// Converts a `u8` into a [`CipherMode`]. Never fails.
624+ ///
625+ /// Shadows `<CipherMode as TryFrom<u8>>::try_from` so existing
626+ /// `CipherMode::try_from(..)` call sites receive a deprecation warning;
627+ /// both will be removed together in a future release.
628+ ///
629+ /// # Errors
630+ ///
631+ /// Never returns `Err`; every byte value is a valid cipher mode.
632+ #[ deprecated( since = "0.36.0" , note = "use `CipherMode::from_byte`" ) ]
633+ #[ allow( clippy:: should_implement_trait) ]
634+ #[ inline]
635+ pub const fn try_from ( value : u8 ) -> Result < Self , UnknownValueError > {
636+ Ok ( Self :: from_byte ( value) )
637+ }
638+
639+ /// Returns `true` if this value is reserved for future PNA specification
640+ /// (unassigned and raw value < 128).
606641 #[ inline]
607642 pub const fn is_reserved ( self ) -> bool {
608- matches ! ( self , Self :: Reserved ( _ ) )
643+ ! matches ! ( self . 0 , 0 ..= 1 ) && self . 0 < 128
609644 }
610645
611- /// Returns `true` if this is a private value.
646+ /// Returns `true` if this is an application-specific private value
647+ /// (raw value >= 128).
612648 #[ inline]
613649 pub const fn is_private ( self ) -> bool {
614- matches ! ( self , Self :: Private ( _) )
650+ self . 0 >= 128
651+ }
652+ }
653+
654+ impl fmt:: Debug for CipherMode {
655+ #[ inline]
656+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
657+ match * self {
658+ Self :: CBC => f. write_str ( "CBC" ) ,
659+ Self :: CTR => f. write_str ( "CTR" ) ,
660+ Self ( v) if v < 128 => f. debug_tuple ( "Reserved" ) . field ( & v) . finish ( ) ,
661+ Self ( v) => f. debug_tuple ( "Private" ) . field ( & v) . finish ( ) ,
662+ }
615663 }
616664}
617665
666+ /// Infallible; kept for backward compatibility with the former enum-based
667+ /// API and scheduled for removal in a future release. Use
668+ /// [`CipherMode::from_byte`] instead.
618669impl TryFrom < u8 > for CipherMode {
619670 type Error = UnknownValueError ;
620671
621672 #[ inline]
622673 fn try_from ( value : u8 ) -> Result < Self , Self :: Error > {
623- match value {
624- 0 => Ok ( Self :: CBC ) ,
625- 1 => Ok ( Self :: CTR ) ,
626- v if v < 128 => Ok ( Self :: Reserved ( v) ) ,
627- v => Ok ( Self :: Private ( v) ) ,
628- }
674+ Ok ( Self :: from_byte ( value) )
629675 }
630676}
631677
@@ -1665,4 +1711,64 @@ mod tests {
16651711 . unwrap_err ( ) ;
16661712 assert_eq ! ( err. kind( ) , io:: ErrorKind :: Unsupported ) ;
16671713 }
1714+
1715+ #[ test]
1716+ fn cipher_mode_round_trips_all_byte_values ( ) {
1717+ for v in 0 ..=u8:: MAX {
1718+ assert_eq ! ( CipherMode :: from_byte( v) . to_byte( ) , v) ;
1719+ }
1720+ }
1721+
1722+ #[ test]
1723+ fn cipher_mode_known_constants_map_to_spec_bytes ( ) {
1724+ assert_eq ! ( CipherMode :: CBC . to_byte( ) , 0 ) ;
1725+ assert_eq ! ( CipherMode :: CTR . to_byte( ) , 1 ) ;
1726+ }
1727+
1728+ #[ test]
1729+ fn cipher_mode_new_private_boundary ( ) {
1730+ assert_eq ! ( CipherMode :: new_private( 0 ) , None ) ;
1731+ assert_eq ! ( CipherMode :: new_private( 127 ) , None ) ;
1732+ assert_eq ! (
1733+ CipherMode :: new_private( 128 ) ,
1734+ Some ( CipherMode :: from_byte( 128 ) )
1735+ ) ;
1736+ assert_eq ! (
1737+ CipherMode :: new_private( 255 ) ,
1738+ Some ( CipherMode :: from_byte( 255 ) )
1739+ ) ;
1740+ }
1741+
1742+ #[ test]
1743+ fn cipher_mode_predicates ( ) {
1744+ assert ! ( !CipherMode :: CBC . is_reserved( ) ) ;
1745+ assert ! ( !CipherMode :: CTR . is_reserved( ) ) ;
1746+ assert ! ( !CipherMode :: CTR . is_private( ) ) ;
1747+ assert ! ( CipherMode :: from_byte( 2 ) . is_reserved( ) ) ;
1748+ assert ! ( CipherMode :: from_byte( 127 ) . is_reserved( ) ) ;
1749+ assert ! ( !CipherMode :: from_byte( 127 ) . is_private( ) ) ;
1750+ assert ! ( !CipherMode :: from_byte( 128 ) . is_reserved( ) ) ;
1751+ assert ! ( CipherMode :: from_byte( 128 ) . is_private( ) ) ;
1752+ assert ! ( CipherMode :: from_byte( 255 ) . is_private( ) ) ;
1753+ }
1754+
1755+ #[ test]
1756+ fn cipher_mode_debug_matches_former_enum_output ( ) {
1757+ assert_eq ! ( format!( "{:?}" , CipherMode :: CBC ) , "CBC" ) ;
1758+ assert_eq ! ( format!( "{:?}" , CipherMode :: CTR ) , "CTR" ) ;
1759+ assert_eq ! ( format!( "{:?}" , CipherMode :: from_byte( 2 ) ) , "Reserved(2)" ) ;
1760+ assert_eq ! ( format!( "{:?}" , CipherMode :: from_byte( 200 ) ) , "Private(200)" ) ;
1761+ }
1762+
1763+ #[ allow( deprecated) ]
1764+ #[ test]
1765+ fn cipher_mode_try_from_is_infallible_and_matches_from_byte ( ) {
1766+ for v in 0 ..=u8:: MAX {
1767+ assert_eq ! ( CipherMode :: try_from( v) . unwrap( ) , CipherMode :: from_byte( v) ) ;
1768+ assert_eq ! (
1769+ <CipherMode as TryFrom <u8 >>:: try_from( v) . unwrap( ) ,
1770+ CipherMode :: from_byte( v)
1771+ ) ;
1772+ }
1773+ }
16681774}
0 commit comments