1
1
use std:: mem:: transmute;
2
2
use std:: fmt;
3
- # [ cfg ( feature= "unstable" ) ]
3
+ use std :: error :: Error ;
4
4
use std:: ascii:: AsciiExt ;
5
5
6
6
use AsciiCast ;
@@ -279,7 +279,7 @@ pub enum Ascii {
279
279
}
280
280
281
281
impl Ascii {
282
- /// Constructs an Ascii character from a `char`.
282
+ /// Constructs an Ascii character from a `char` or `u8` .
283
283
///
284
284
/// # Failure
285
285
///
@@ -292,11 +292,13 @@ impl Ascii {
292
292
/// assert_eq!(a.as_char(), 'g');
293
293
/// ```
294
294
#[ inline]
295
- pub fn from ( ch : char ) -> Result < Ascii , ( ) > {
296
- unsafe { if ch as u32 <= 0x7F {
297
- return Ok ( ch. to_ascii_nocheck ( ) ) ;
298
- } }
299
- Err ( ( ) )
295
+ pub fn from < C : IntoAscii > ( ch : C ) -> Result < Self , ( ) > {
296
+ ch. into_ascii ( ) . map_err ( |_| ( ) )
297
+ }
298
+
299
+ /// Constructs an Ascii character from a `char` or `u8` without any checks.
300
+ pub unsafe fn from_unchecked < C : IntoAscii > ( ch : C ) -> Self {
301
+ ch. into_ascii_unchecked ( )
300
302
}
301
303
302
304
/// Constructs an Ascii character from a `u8`.
@@ -530,10 +532,73 @@ impl<'a> AsciiCast<'a> for char {
530
532
}
531
533
}
532
534
535
+
536
+
537
+ const ERRORMSG_CHAR : & ' static str = "not an ASCII character" ;
538
+ /// Error returned by `IntoAscii.into_ascii()` when the parameter is greater than 127.
539
+ #[ derive( PartialEq ) ]
540
+ pub struct IntoAsciiError ( ( ) ) ;
541
+ impl fmt:: Debug for IntoAsciiError {
542
+ fn fmt ( & self , fmtr : & mut fmt:: Formatter ) -> fmt:: Result {
543
+ write ! ( fmtr, "{}" , ERRORMSG_CHAR )
544
+ }
545
+ }
546
+ impl fmt:: Display for IntoAsciiError {
547
+ fn fmt ( & self , fmtr : & mut fmt:: Formatter ) -> fmt:: Result {
548
+ write ! ( fmtr, "{}" , ERRORMSG_CHAR )
549
+ }
550
+ }
551
+ impl Error for IntoAsciiError {
552
+ fn description ( & self ) -> & ' static str {
553
+ ERRORMSG_CHAR
554
+ }
555
+ }
556
+
557
+
558
+ /// Trait for converting `char` and `u8` into `Ascii`.
559
+ pub trait IntoAscii : AsciiExt {
560
+ /// Convert to `Ascii` without checking if it's less than 128.
561
+ unsafe fn into_ascii_unchecked ( self ) -> Ascii ;
562
+ /// Convert to `Ascii`.
563
+ fn into_ascii ( self ) -> Result < Ascii , IntoAsciiError > ;
564
+ }
565
+
566
+ #[ cfg( feature = "unstable" ) ]
567
+ impl IntoAscii for Ascii {
568
+ fn into_ascii ( self ) -> Result < Ascii , IntoAsciiError > {
569
+ Ok ( self )
570
+ }
571
+ unsafe fn into_ascii_unchecked ( self ) -> Ascii {
572
+ self
573
+ }
574
+ }
575
+ impl IntoAscii for u8 {
576
+ fn into_ascii ( self ) -> Result < Ascii , IntoAsciiError > {
577
+ unsafe { if self <= 0x7F {
578
+ return Ok ( self . into_ascii_unchecked ( ) ) ;
579
+ } }
580
+ Err ( IntoAsciiError ( ( ) ) )
581
+ }
582
+ unsafe fn into_ascii_unchecked ( self ) -> Ascii {
583
+ transmute ( self )
584
+ }
585
+ }
586
+ impl IntoAscii for char {
587
+ fn into_ascii ( self ) -> Result < Ascii , IntoAsciiError > {
588
+ unsafe { if self as u32 <= 0x7F {
589
+ return Ok ( self . into_ascii_unchecked ( ) ) ;
590
+ } }
591
+ Err ( IntoAsciiError ( ( ) ) )
592
+ }
593
+ unsafe fn into_ascii_unchecked ( self ) -> Ascii {
594
+ ( self as u8 ) . into_ascii_unchecked ( )
595
+ }
596
+ }
597
+
533
598
#[ cfg( test) ]
534
599
mod tests {
535
600
use AsciiCast ;
536
- use super :: Ascii ;
601
+ use super :: { Ascii , IntoAscii , IntoAsciiError } ;
537
602
538
603
#[ test]
539
604
fn to_ascii ( ) {
@@ -544,6 +609,15 @@ mod tests {
544
609
assert_eq ! ( 'λ' . to_ascii( ) , Err ( ( ) ) ) ;
545
610
}
546
611
612
+ #[ test]
613
+ fn into_ascii ( ) {
614
+ fn generic < C : IntoAscii > ( c : C ) -> Result < Ascii , IntoAsciiError > {
615
+ c. into_ascii ( )
616
+ }
617
+ assert_eq ! ( generic( 'A' ) , Ok ( Ascii :: A ) ) ;
618
+ assert_eq ! ( generic( b'A' ) , Ok ( Ascii :: A ) ) ;
619
+ }
620
+
547
621
#[ test]
548
622
fn as_byte ( ) {
549
623
assert_eq ! ( 65u8 . to_ascii( ) . unwrap( ) . as_byte( ) , 65u8 ) ;
0 commit comments