1use std::borrow::Cow::{self, Borrowed, Owned};
5
6use crate::external_idna;
7
8#[derive(Copy, Clone, Debug, Eq, PartialEq)]
10pub struct Error;
11
12pub fn to_ascii(s: &str) -> Result<Cow<str>, Error> {
16 if s.is_ascii() {
17 Ok(Borrowed(s))
18 } else {
19 external_idna::domain_to_ascii(s)
20 .map(Owned)
21 .map_err(|_| Error)
22 }
23}
24
25pub fn to_unicode(s: &str) -> Result<Cow<str>, Error> {
29 let is_unicode = s.split('.').any(|s| s.starts_with("xn--"));
30
31 if is_unicode {
32 match external_idna::domain_to_unicode(s) {
33 (s, Ok(_)) => Ok(Owned(s)),
34 (_, Err(_)) => Err(Error),
35 }
36 } else {
37 Ok(Borrowed(s))
38 }
39}
40
41#[cfg(test)]
42mod test {
43 use super::{to_ascii, to_unicode};
44
45 static SAMPLE_HOSTS: &'static [(&'static str, &'static str)] = &[
46 ("bücher.de.", "xn--bcher-kva.de."),
47 ("ουτοπία.δπθ.gr.", "xn--kxae4bafwg.xn--pxaix.gr."),
48 ("bücher.de", "xn--bcher-kva.de"),
50 ("ουτοπία.δπθ.gr", "xn--kxae4bafwg.xn--pxaix.gr"),
51 ];
52
53 #[test]
54 fn test_hosts() {
55 for &(uni, ascii) in SAMPLE_HOSTS {
56 assert_eq!(to_ascii(uni).unwrap(), ascii);
57 assert_eq!(to_unicode(ascii).unwrap(), uni);
58
59 assert_eq!(to_ascii(ascii).unwrap(), ascii);
61 assert_eq!(to_unicode(uni).unwrap(), uni);
62 }
63 }
64}