format.rs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // Copyright 2013-2015 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 `fmt::Display`.
  13. use std::fmt::{self, 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: fmt::Display> fmt::Display 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 {
  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)`.
  40. pub password: Option<&'a str>
  41. }
  42. impl<'a> fmt::Display 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. if let Some(password) = self.password {
  47. try!(formatter.write_str(":"));
  48. try!(formatter.write_str(password));
  49. }
  50. try!(formatter.write_str("@"));
  51. }
  52. Ok(())
  53. }
  54. }
  55. /// Formatter for URLs which ignores the fragment field.
  56. pub struct UrlNoFragmentFormatter<'a> {
  57. pub url: &'a Url
  58. }
  59. impl<'a> fmt::Display for UrlNoFragmentFormatter<'a> {
  60. fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
  61. try!(formatter.write_str(&self.url.scheme));
  62. try!(formatter.write_str(":"));
  63. try!(self.url.scheme_data.fmt(formatter));
  64. if let Some(ref query) = self.url.query {
  65. try!(formatter.write_str("?"));
  66. try!(formatter.write_str(query));
  67. }
  68. Ok(())
  69. }
  70. }
  71. /// Formatting Tests
  72. #[cfg(test)]
  73. mod tests {
  74. use super::super::Url;
  75. use super::{PathFormatter, UserInfoFormatter};
  76. #[test]
  77. fn path_formatting() {
  78. let data = [
  79. (vec![], "/"),
  80. (vec![""], "/"),
  81. (vec!["test", "path"], "/test/path"),
  82. (vec!["test", "path", ""], "/test/path/")
  83. ];
  84. for &(ref path, result) in &data {
  85. assert_eq!(PathFormatter {
  86. path: path
  87. }.to_string(), result.to_string());
  88. }
  89. }
  90. #[test]
  91. fn userinfo_formatting() {
  92. // Test data as (username, password, result) tuples.
  93. let data = [
  94. ("", None, ""),
  95. ("", Some(""), ":@"),
  96. ("", Some("password"), ":password@"),
  97. ("username", None, "username@"),
  98. ("username", Some(""), "username:@"),
  99. ("username", Some("password"), "username:password@")
  100. ];
  101. for &(username, password, result) in &data {
  102. assert_eq!(UserInfoFormatter {
  103. username: username,
  104. password: password
  105. }.to_string(), result.to_string());
  106. }
  107. }
  108. #[test]
  109. fn relative_scheme_url_formatting() {
  110. let data = [
  111. ("http://example.com/", "http://example.com/"),
  112. ("http://addslash.com", "http://addslash.com/"),
  113. ("http://@emptyuser.com/", "http://emptyuser.com/"),
  114. ("http://:@emptypass.com/", "http://:@emptypass.com/"),
  115. ("http://user@user.com/", "http://user@user.com/"),
  116. ("http://user:pass@userpass.com/", "http://user:pass@userpass.com/"),
  117. ("http://slashquery.com/path/?q=something", "http://slashquery.com/path/?q=something"),
  118. ("http://noslashquery.com/path?q=something", "http://noslashquery.com/path?q=something")
  119. ];
  120. for &(input, result) in &data {
  121. let url = Url::parse(input).unwrap();
  122. assert_eq!(url.to_string(), result.to_string());
  123. }
  124. }
  125. }