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 `u8`, ` char` or other character type .
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,79 @@ impl<'a> AsciiCast<'a> for char {
530
532
}
531
533
}
532
534
535
+
536
+ /// Error returned by `IntoAscii`.
537
+ #[ derive( PartialEq ) ]
538
+ pub struct IntoAsciiError ( ( ) ) ;
539
+
540
+ const ERRORMSG_CHAR : & ' static str = "not an ASCII character" ;
541
+
542
+ impl fmt:: Debug for IntoAsciiError {
543
+ fn fmt ( & self , fmtr : & mut fmt:: Formatter ) -> fmt:: Result {
544
+ write ! ( fmtr, "{}" , ERRORMSG_CHAR )
545
+ }
546
+ }
547
+
548
+ impl fmt:: Display for IntoAsciiError {
549
+ fn fmt ( & self , fmtr : & mut fmt:: Formatter ) -> fmt:: Result {
550
+ write ! ( fmtr, "{}" , ERRORMSG_CHAR )
551
+ }
552
+ }
553
+
554
+ impl Error for IntoAsciiError {
555
+ fn description ( & self ) -> & ' static str {
556
+ ERRORMSG_CHAR
557
+ }
558
+ }
559
+
560
+
561
+ /// Convert `char`, `u8` and other character types to `Ascii`.
562
+ pub trait IntoAscii : AsciiExt {
563
+ /// Convert to `Ascii` without checking that it is an ASCII character.
564
+ unsafe fn into_ascii_unchecked ( self ) -> Ascii ;
565
+ /// Convert to `Ascii`.
566
+ fn into_ascii ( self ) -> Result < Ascii , IntoAsciiError > ;
567
+ }
568
+
569
+ #[ cfg( feature = "unstable" ) ]
570
+ impl IntoAscii for Ascii {
571
+ fn into_ascii ( self ) -> Result < Ascii , IntoAsciiError > {
572
+ Ok ( self )
573
+ }
574
+ unsafe fn into_ascii_unchecked ( self ) -> Ascii {
575
+ self
576
+ }
577
+ }
578
+
579
+ impl IntoAscii for u8 {
580
+ fn into_ascii ( self ) -> Result < Ascii , IntoAsciiError > {
581
+ unsafe { if self <= 0x7F {
582
+ return Ok ( self . into_ascii_unchecked ( ) ) ;
583
+ } }
584
+ Err ( IntoAsciiError ( ( ) ) )
585
+ }
586
+ unsafe fn into_ascii_unchecked ( self ) -> Ascii {
587
+ transmute ( self )
588
+ }
589
+ }
590
+
591
+ impl IntoAscii for char {
592
+ fn into_ascii ( self ) -> Result < Ascii , IntoAsciiError > {
593
+ unsafe { if self as u32 <= 0x7F {
594
+ return Ok ( self . into_ascii_unchecked ( ) ) ;
595
+ } }
596
+ Err ( IntoAsciiError ( ( ) ) )
597
+ }
598
+ unsafe fn into_ascii_unchecked ( self ) -> Ascii {
599
+ ( self as u8 ) . into_ascii_unchecked ( )
600
+ }
601
+ }
602
+
603
+
533
604
#[ cfg( test) ]
534
605
mod tests {
535
606
use AsciiCast ;
536
- use super :: Ascii ;
607
+ use super :: { Ascii , IntoAscii , IntoAsciiError } ;
537
608
538
609
#[ test]
539
610
fn to_ascii ( ) {
@@ -544,6 +615,15 @@ mod tests {
544
615
assert_eq ! ( 'λ' . to_ascii( ) , Err ( ( ) ) ) ;
545
616
}
546
617
618
+ #[ test]
619
+ fn into_ascii ( ) {
620
+ fn generic < C : IntoAscii > ( c : C ) -> Result < Ascii , IntoAsciiError > {
621
+ c. into_ascii ( )
622
+ }
623
+ assert_eq ! ( generic( 'A' ) , Ok ( Ascii :: A ) ) ;
624
+ assert_eq ! ( generic( b'A' ) , Ok ( Ascii :: A ) ) ;
625
+ }
626
+
547
627
#[ test]
548
628
fn as_byte ( ) {
549
629
assert_eq ! ( 65u8 . to_ascii( ) . unwrap( ) . as_byte( ) , 65u8 ) ;
0 commit comments