Skip to content

Commit

Permalink
Add encoder for port
Browse files Browse the repository at this point in the history
  • Loading branch information
yescallop committed Jun 7, 2024
1 parent 1410d8e commit 00a1715
Show file tree
Hide file tree
Showing 11 changed files with 42 additions and 49 deletions.
7 changes: 5 additions & 2 deletions fuzz/fuzz_targets/against_iref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ fuzz_target!(|data: &str| {
u2.scheme().map(|s| s.as_str())
);
assert_eq!(
u1.authority()
.map(|a| (a.userinfo().map(|s| s.as_str()), a.host(), a.port())),
u1.authority().map(|a| (
a.userinfo().map(|s| s.as_str()),
a.host(),
a.port().map(|s| s.as_str())
)),
u2.authority().map(|a| (
a.user_info().map(|s| s.as_str()),
a.host().as_str(),
Expand Down
7 changes: 5 additions & 2 deletions fuzz/fuzz_targets/against_iri_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ fuzz_target!(|data: &str| {

assert_eq!(u1.scheme().map(|s| s.as_str()), u2.scheme_str());
assert_eq!(
u1.authority()
.map(|a| (a.userinfo().map(|s| s.as_str()), a.host(), a.port())),
u1.authority().map(|a| (
a.userinfo().map(|s| s.as_str()),
a.host(),
a.port().map(|s| s.as_str())
)),
u2.authority_components()
.map(|a| (a.userinfo(), a.host(), a.port()))
);
Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/against_uriparser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ unsafe fn check(data: &str, cstr: &CStr) {
}
}

assert_text_eq(a.port(), uri1.portText);
assert_text_eq(a.port().map(|s| s.as_str()), uri1.portText);
} else {
assert_text_eq(None, uri1.userInfo);
assert_text_eq(None, uri1.hostText);
Expand Down
16 changes: 1 addition & 15 deletions fuzz/fuzz_targets/build_parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,25 +65,11 @@ impl<'a> HostWrapper<'a> {
}
}

#[derive(Debug, Clone, Copy)]
struct Port<'a>(&'a str);

impl<'a> Arbitrary<'a> for Port<'a> {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
let s: &str = u.arbitrary()?;
if s.bytes().all(|x| x.is_ascii_digit()) {
Ok(Port(s))
} else {
Err(Error::IncorrectFormat)
}
}
}

#[derive(Arbitrary, Clone, Copy, Debug)]
struct Authority<'a> {
userinfo: Option<EStrWrapper<'a, Userinfo>>,
host: HostWrapper<'a>,
port: Option<Port<'a>>,
port: Option<EStrWrapper<'a, Port>>,
}

#[derive(Arbitrary, Clone, Copy, Debug)]
Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fuzz_target!(|data: &str| {
buf.push_str(a.host());
if let Some(p) = a.port() {
buf.push(':');
buf.push_str(p);
buf.push_str(p.as_str());
}
assert_eq!(&buf[start..], a.as_str());
}
Expand Down
20 changes: 7 additions & 13 deletions src/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod state;
use crate::{
component::{Host, Scheme},
encoding::{
encoder::{Fragment, Path, Query, Userinfo},
encoder::{Fragment, Path, Port, Query, Userinfo},
EStr,
},
error::{BuildError, BuildErrorKind},
Expand Down Expand Up @@ -336,36 +336,30 @@ impl<S: To<HostEnd>> Builder<S> {
}
}

pub trait PortLike {
pub trait AsPort {
fn push_to(&self, buf: &mut String);
}

impl PortLike for u16 {
impl AsPort for u16 {
fn push_to(&self, buf: &mut String) {
write!(buf, ":{self}").unwrap();
}
}

impl PortLike for &str {
impl AsPort for &EStr<Port> {
fn push_to(&self, buf: &mut String) {
assert!(self.bytes().all(|x| x.is_ascii_digit()), "invalid port");
buf.push(':');
buf.push_str(self);
buf.push_str(self.as_str());
}
}

impl<S: To<PortEnd>> Builder<S> {
/// Sets the [port] subcomponent of authority.
///
/// This method takes either a `u16` or `&str` as argument.
///
/// # Panics
///
/// Panics if an input string is not a valid port according to
/// [Section 3.2.3 of RFC 3986][port].
/// This method takes either a `u16` or `&EStr<Port>` as argument.
///
/// [port]: https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.3
pub fn port<T: PortLike>(mut self, port: T) -> Builder<PortEnd> {
pub fn port<P: AsPort>(mut self, port: P) -> Builder<PortEnd> {
port.push_to(&mut self.inner.buf);
self.cast()
}
Expand Down
16 changes: 8 additions & 8 deletions src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::{
encoding::{
encoder::{RegName, Userinfo},
encoder::{Port, RegName, Userinfo},
table, EStr, EString,
},
internal::{AuthMeta, HostMeta},
Expand Down Expand Up @@ -292,29 +292,29 @@ impl<'i, 'o, T: BorrowOrShare<'i, 'o, str>> Authority<T> {
/// # Examples
///
/// ```
/// use fluent_uri::Uri;
/// use fluent_uri::{encoding::EStr, Uri};
///
/// let uri = Uri::parse("//localhost:4673/")?;
/// let auth = uri.authority().unwrap();
/// assert_eq!(auth.port(), Some("4673"));
/// assert_eq!(auth.port(), Some(EStr::new_or_panic("4673")));
///
/// let uri = Uri::parse("//localhost:/")?;
/// let auth = uri.authority().unwrap();
/// assert_eq!(auth.port(), Some(""));
/// assert_eq!(auth.port(), Some(EStr::EMPTY));
///
/// let uri = Uri::parse("//localhost/")?;
/// let auth = uri.authority().unwrap();
/// assert_eq!(auth.port(), None);
///
/// let uri = Uri::parse("//localhost:123456/")?;
/// let auth = uri.authority().unwrap();
/// assert_eq!(auth.port(), Some("123456"));
/// assert_eq!(auth.port(), Some(EStr::new_or_panic("123456")));
/// # Ok::<_, fluent_uri::error::ParseError>(())
/// ```
#[must_use]
pub fn port(&'i self) -> Option<&'o str> {
pub fn port(&'i self) -> Option<&'o EStr<Port>> {
let (host_end, end) = (self.host_bounds().1, self.end());
(host_end != end).then(|| self.uri.slice(host_end + 1, end))
(host_end != end).then(|| self.uri.eslice(host_end + 1, end))
}

/// Converts the [port] subcomponent to `u16`, if present.
Expand Down Expand Up @@ -350,7 +350,7 @@ impl<'i, 'o, T: BorrowOrShare<'i, 'o, str>> Authority<T> {
pub fn port_to_u16(&'i self) -> Result<Option<u16>, ParseIntError> {
self.port()
.filter(|port| !port.is_empty())
.map(str::parse)
.map(|port| port.as_str().parse())
.transpose()
}

Expand Down
7 changes: 7 additions & 0 deletions src/encoding/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ impl Encoder for RegName {
const TABLE: &'static Table = REG_NAME;
}

/// An encoder for port.
pub struct Port(());

impl Encoder for Port {
const TABLE: &'static Table = DIGIT;
}

/// An encoder for path.
///
/// [`EStr`] has [extension methods] for the path component.
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ use internal::{Meta, ToUri, Value};
/// assert_eq!(auth.userinfo().unwrap(), "user");
/// assert_eq!(auth.host(), "example.com");
/// assert!(matches!(auth.host_parsed(), Host::RegName(name) if name == "example.com"));
/// assert_eq!(auth.port(), Some("8042"));
/// assert_eq!(auth.port().unwrap(), "8042");
/// assert_eq!(auth.port_to_u16(), Ok(Some(8042)));
///
/// assert_eq!(uri.path(), "/over/there");
Expand Down
2 changes: 1 addition & 1 deletion src/normalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub(crate) fn normalize(u: Uri<&str>) -> Uri<String> {
if let Some(port) = auth.port() {
if !port.is_empty() {
buf.push(':');
buf.push_str(port);
buf.push_str(port.as_str());
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions tests/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ fn parse_absolute() {
assert_eq!(a.host(), "192.0.2.16");
#[cfg(feature = "net")]
assert!(matches!(a.host_parsed(), Host::Ipv4(addr) if addr == Ipv4Addr::new(192, 0, 2, 16)));
assert_eq!(a.port(), Some("80"));
assert_eq!(a.port(), Some(EStr::new_or_panic("80")));
assert_eq!(u.path(), "/");
assert_eq!(u.query(), None);
assert_eq!(u.fragment(), None);
Expand All @@ -106,7 +106,7 @@ fn parse_absolute() {
assert_eq!(a.userinfo(), None);
assert_eq!(a.host(), "example.com");
assert!(matches!(a.host_parsed(), Host::RegName(name) if name == "example.com"));
assert_eq!(a.port(), Some("8042"));
assert_eq!(a.port(), Some(EStr::new_or_panic("8042")));
assert_eq!(u.path(), "/over/there");
assert_eq!(u.query(), Some(EStr::new_or_panic("name=ferret")));
assert_eq!(u.fragment(), Some(EStr::new_or_panic("nose")));
Expand Down Expand Up @@ -147,7 +147,7 @@ fn parse_absolute() {
assert_eq!(a.host(), "127.0.0.1");
#[cfg(feature = "net")]
assert!(matches!(a.host_parsed(), Host::Ipv4(addr) if addr == Ipv4Addr::new(127, 0, 0, 1)));
assert_eq!(a.port(), Some(""));
assert_eq!(a.port(), Some(EStr::EMPTY));
assert_eq!(u.path(), "/");
assert_eq!(u.query(), None);
assert_eq!(u.fragment(), None);
Expand All @@ -160,7 +160,7 @@ fn parse_absolute() {
assert_eq!(a.host(), "127.0.0.1");
#[cfg(feature = "net")]
assert!(matches!(a.host_parsed(), Host::Ipv4(addr) if addr == Ipv4Addr::new(127, 0, 0, 1)));
assert_eq!(a.port(), Some("8080"));
assert_eq!(a.port(), Some(EStr::new_or_panic("8080")));
assert_eq!(u.path(), "/");
assert_eq!(u.query(), None);
assert_eq!(u.fragment(), None);
Expand All @@ -173,7 +173,7 @@ fn parse_absolute() {
assert_eq!(a.host(), "127.0.0.1");
#[cfg(feature = "net")]
assert!(matches!(a.host_parsed(), Host::Ipv4(addr) if addr == Ipv4Addr::new(127, 0, 0, 1)));
assert_eq!(a.port(), Some("80808"));
assert_eq!(a.port(), Some(EStr::new_or_panic("80808")));
assert_eq!(u.path(), "/");
assert_eq!(u.query(), None);
assert_eq!(u.fragment(), None);
Expand Down

0 comments on commit 00a1715

Please sign in to comment.