format.rs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // Copyright 2013-2014 Simon Sapin.
  2. //
  3. // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
  4. // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
  5. // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
  6. // option. This file may not be copied, modified, or distributed
  7. // except according to those terms.
  8. //! Formatting utilities for URLs.
  9. //!
  10. //! These formatters can be used to coerce various URL parts into strings.
  11. //!
  12. //! You can use `<formatter>.to_string()`, as the formatters implement `Show`.
  13. use std::fmt::{self, Show, Formatter};
  14. use super::Url;
  15. /// Formatter and serializer for URL path data.
  16. pub struct PathFormatter<'a, T:'a> {
  17. /// The path as a slice of string-like objects (String or &str).
  18. pub path: &'a [T]
  19. }
  20. impl<'a, T: Str + Show> Show for PathFormatter<'a, T> {
  21. fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
  22. if self.path.is_empty() {
  23. formatter.write_str("/")
  24. } else {
  25. for path_part in self.path.iter() {
  26. try!("/".fmt(formatter));
  27. try!(path_part.fmt(formatter));
  28. }
  29. Ok(())
  30. }
  31. }
  32. }
  33. /// Formatter and serializer for URL username and password data.
  34. pub struct UserInfoFormatter<'a> {
  35. /// URL username as a string slice.
  36. pub username: &'a str,
  37. /// URL password as an optional string slice.
  38. ///
  39. /// You can convert an `Option<String>` with `.as_ref().map(|s| s.as_slice())`.
  40. pub password: Option<&'a str>
  41. }
  42. impl<'a> Show for UserInfoFormatter<'a> {
  43. fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
  44. if !self.username.is_empty() || self.password.is_some() {
  45. try!(formatter.write_str(self.username));
  46. match self.password {
  47. None => (),
  48. Some(password) => {
  49. try!(formatter.write_str(":"));
  50. try!(formatter.write_str(password));
  51. }
  52. }
  53. try!(formatter.write_str("@"));
  54. }
  55. Ok(())
  56. }
  57. }
  58. /// Formatter for URLs which ignores the fragment field.
  59. pub struct UrlNoFragmentFormatter<'a> {
  60. pub url: &'a Url
  61. }
  62. impl<'a> Show for UrlNoFragmentFormatter<'a> {
  63. fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
  64. try!(formatter.write_str(self.url.scheme.as_slice()));
  65. try!(formatter.write_str(":"));
  66. try!(self.url.scheme_data.fmt(formatter));
  67. match self.url.query {
  68. None => (),
  69. Some(ref query) => {
  70. try!(formatter.write_str("?"));
  71. try!(formatter.write_str(query.as_slice()));
  72. }
  73. }
  74. Ok(())
  75. }
  76. }
  77. /// Formatting Tests
  78. #[cfg(test)]
  79. mod tests {
  80. use super::super::Url;
  81. use super::{PathFormatter, UserInfoFormatter};
  82. #[test]
  83. fn path_formatting() {
  84. let data = [
  85. (vec![], "/"),
  86. (vec![""], "/"),
  87. (vec!["test", "path"], "/test/path"),
  88. (vec!["test", "path", ""], "/test/path/")
  89. ];
  90. for &(ref path, result) in data.iter() {
  91. assert_eq!(PathFormatter {
  92. path: path.as_slice()
  93. }.to_string(), result.to_string());
  94. }
  95. }
  96. #[test]
  97. fn userinfo_formatting() {
  98. // Test data as (username, password, result) tuples.
  99. let data = [
  100. ("", None, ""),
  101. ("", Some(""), ":@"),
  102. ("", Some("password"), ":password@"),
  103. ("username", None, "username@"),
  104. ("username", Some(""), "username:@"),
  105. ("username", Some("password"), "username:password@")
  106. ];
  107. for &(username, password, result) in data.iter() {
  108. assert_eq!(UserInfoFormatter {
  109. username: username,
  110. password: password
  111. }.to_string(), result.to_string());
  112. }
  113. }
  114. #[test]
  115. fn relative_scheme_url_formatting() {
  116. let data = [
  117. ("http://example.com/", "http://example.com/"),
  118. ("http://addslash.com", "http://addslash.com/"),
  119. ("http://@emptyuser.com/", "http://emptyuser.com/"),
  120. ("http://:@emptypass.com/", "http://:@emptypass.com/"),
  121. ("http://user@user.com/", "http://user@user.com/"),
  122. ("http://user:pass@userpass.com/", "http://user:pass@userpass.com/"),
  123. ("http://slashquery.com/path/?q=something", "http://slashquery.com/path/?q=something"),
  124. ("http://noslashquery.com/path?q=something", "http://noslashquery.com/path?q=something")
  125. ];
  126. for &(input, result) in data.iter() {
  127. let url = Url::parse(input).unwrap();
  128. assert_eq!(url.to_string(), result.to_string());
  129. }
  130. }
  131. }