1 use libc::{c_char, c_uchar}; 2 use translate::FromGlib; 3 use translate::ToGlib; 4 5 /// Wrapper for values where C functions expect a plain C `char` 6 /// 7 /// Consider the following C function prototype from glib: 8 /// 9 /// ```C 10 /// void g_key_file_set_list_separator (GKeyFile *key_file, gchar separator); 11 /// ``` 12 /// 13 /// This function plainly expects a byte as the `separator` argument. However, 14 /// having this function exposed to Rust as the following would be inconvenient: 15 /// 16 /// ```ignore 17 /// impl KeyFile { 18 /// pub fn set_list_separator(&self, separator: libc:c_char) { } 19 /// } 20 /// ``` 21 /// 22 /// This would be inconvenient because users would have to do the conversion from a Rust `char` to an `libc::c_char` by hand, which is just a type alias 23 /// for `i8` on most system. 24 /// 25 /// This `Char` type is a wrapper over an `libc::c_char`, so that we can pass it to Glib or C functions. 26 /// The check for whether a Rust `char` (a Unicode scalar value) actually fits in a `libc::c_char` is 27 /// done in the `new` function; see its documentation for details. 28 /// 29 /// The inner `libc::c_char` (which is equivalent to `i8` can be extracted with `.0`, or 30 /// by calling `my_char.to_glib()`. 31 #[derive(Debug, Copy, Clone, Eq, PartialEq)] 32 pub struct Char(pub c_char); 33 34 impl Char { 35 /// Creates a `Some(Char)` if the given `char` is representable as an `libc::c_char` 36 /// 37 /// # Example 38 /// ```ignore 39 /// extern "C" fn have_a_byte(b: libc::c_char); 40 /// 41 /// let a = Char::new('a').unwrap(); 42 /// assert!(a.0 == 65); 43 /// have_a_byte(a.to_glib()); 44 /// 45 /// let not_representable = Char::new('☔'); 46 /// assert!(not_representable.is_none()); 47 /// ``` new(c: char) -> Option<Char>48 pub fn new(c: char) -> Option<Char> { 49 if c as u32 > 255 { 50 None 51 } else { 52 Some(Char(c as c_char)) 53 } 54 } 55 } 56 57 impl From<Char> for char { from(c: Char) -> char58 fn from(c: Char) -> char { 59 c.0 as u8 as char 60 } 61 } 62 63 #[doc(hidden)] 64 impl FromGlib<c_char> for Char { from_glib(value: c_char) -> Self65 fn from_glib(value: c_char) -> Self { 66 Char(value) 67 } 68 } 69 70 #[doc(hidden)] 71 impl ToGlib for Char { 72 type GlibType = c_char; 73 to_glib(&self) -> c_char74 fn to_glib(&self) -> c_char { 75 self.0 76 } 77 } 78 79 /// Wrapper for values where C functions expect a plain C `unsigned char` 80 /// 81 /// This `UChar` type is a wrapper over an `libc::c_uchar`, so that we can pass it to Glib or C functions. 82 /// The check for whether a Rust `char` (a Unicode scalar value) actually fits in a `libc::c_uchar` is 83 /// done in the `new` function; see its documentation for details. 84 /// 85 /// The inner `libc::c_uchar` (which is equivalent to `u8` can be extracted with `.0`, or 86 /// by calling `my_char.to_glib()`. 87 #[derive(Debug, Copy, Clone, Eq, PartialEq)] 88 pub struct UChar(pub c_uchar); 89 90 impl UChar { 91 /// Creates a `Some(UChar)` if the given `char` is representable as an `libc::c_uchar` 92 /// 93 /// # Example 94 /// ```ignore 95 /// extern "C" fn have_a_byte(b: libc::c_uchar); 96 /// 97 /// let a = Char::new('a').unwrap(); 98 /// assert!(a.0 == 65); 99 /// have_a_byte(a.to_glib()); 100 /// 101 /// let not_representable = Char::new('☔'); 102 /// assert!(not_representable.is_none()); 103 /// ``` new(c: char) -> Option<UChar>104 pub fn new(c: char) -> Option<UChar> { 105 if c as u32 > 255 { 106 None 107 } else { 108 Some(UChar(c as c_uchar)) 109 } 110 } 111 } 112 113 impl From<UChar> for char { from(c: UChar) -> char114 fn from(c: UChar) -> char { 115 c.0 as char 116 } 117 } 118 119 #[doc(hidden)] 120 impl FromGlib<c_uchar> for UChar { from_glib(value: c_uchar) -> Self121 fn from_glib(value: c_uchar) -> Self { 122 UChar(value) 123 } 124 } 125 126 #[doc(hidden)] 127 impl ToGlib for UChar { 128 type GlibType = c_uchar; 129 to_glib(&self) -> c_uchar130 fn to_glib(&self) -> c_uchar { 131 self.0 132 } 133 } 134 135 #[cfg(test)] 136 mod tests { 137 use super::*; 138 use translate::from_glib; 139 140 #[test] converts_single_byte_chars()141 fn converts_single_byte_chars() { 142 assert_eq!(Char::new(0 as char), Some(Char(0 as c_char))); 143 assert_eq!(Char::new(255 as char), Some(Char(-1 as i8 as c_char))); 144 assert_eq!(Char::new('ñ'), Some(Char(241 as u8 as c_char))); 145 assert_eq!(UChar::new(0 as char), Some(UChar(0 as c_uchar))); 146 assert_eq!(UChar::new(255 as char), Some(UChar(255 as c_uchar))); 147 assert_eq!(UChar::new('ñ'), Some(UChar(241 as c_uchar))); 148 } 149 150 #[test] refuses_multibyte_chars()151 fn refuses_multibyte_chars() { 152 assert_eq!(Char::new('☔'), None); // no umbrella for you 153 assert_eq!(UChar::new('☔'), None); 154 } 155 156 #[test] into_i8()157 fn into_i8() { 158 assert_eq!(Char::new('A').unwrap().to_glib(), 65 as c_char); 159 } 160 161 #[test] into_u8()162 fn into_u8() { 163 assert_eq!(UChar::new('A').unwrap().to_glib(), 65 as c_uchar); 164 } 165 166 #[test] into_char()167 fn into_char() { 168 assert_eq!(char::from(Char(65 as c_char)), 'A'); 169 assert_eq!('ñ', UChar(241 as c_uchar).into()); 170 } 171 172 #[test] convert_from_glib()173 fn convert_from_glib() { 174 assert_eq!(Char(65 as c_char), from_glib(65 as c_char)); 175 assert_eq!(UChar(241 as c_uchar), from_glib(241 as u8 as c_uchar)); 176 } 177 } 178