#![allow(missing_debug_implementations)]
mod imp;
pub(crate) mod state;
use imp::*;
use state::*;
use crate::{
component::{Authority, Scheme},
imp::{Meta, RiMaybeRef},
pct_enc::EStr,
};
use alloc::string::String;
use core::{fmt, marker::PhantomData};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum BuildError {
NonemptyRootlessPath,
PathStartsWithDoubleSlash,
FirstPathSegmentContainsColon,
}
impl fmt::Display for BuildError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let msg = match self {
Self::NonemptyRootlessPath => {
"when authority is present, path should either be empty or start with '/'"
}
Self::PathStartsWithDoubleSlash => {
"when authority is not present, path should not start with \"//\""
}
Self::FirstPathSegmentContainsColon => {
"when neither scheme nor authority is present, first path segment should not contain ':'"
}
};
f.write_str(msg)
}
}
#[cfg(feature = "impl-error")]
impl crate::Error for BuildError {}
#[must_use]
pub struct Builder<R, S> {
inner: BuilderInner,
_marker: PhantomData<(R, S)>,
}
impl<R, S> Builder<R, S> {
pub(crate) fn new() -> Self {
Self {
inner: BuilderInner {
buf: String::new(),
meta: Meta::default(),
},
_marker: PhantomData,
}
}
}
impl<R, S> Builder<R, S> {
fn cast<T>(self) -> Builder<R, T>
where
S: To<T>,
{
Builder {
inner: self.inner,
_marker: PhantomData,
}
}
pub fn advance<T>(self) -> Builder<R, T>
where
S: AdvanceTo<T>,
{
self.cast()
}
pub fn optional<F, V, T>(self, f: F, opt: Option<V>) -> Builder<R, T>
where
F: FnOnce(Self, V) -> Builder<R, T>,
S: AdvanceTo<T>,
{
match opt {
Some(value) => f(self, value),
None => self.advance(),
}
}
}
impl<R, S: To<SchemeEnd>> Builder<R, S> {
pub fn scheme(mut self, scheme: &Scheme) -> Builder<R, SchemeEnd> {
self.inner.push_scheme(scheme.as_str());
self.cast()
}
}
impl<R: RiMaybeRef, S: To<AuthorityStart>> Builder<R, S> {
pub fn authority_with<F, T>(mut self, f: F) -> Builder<R, AuthorityEnd>
where
F: FnOnce(Builder<R, AuthorityStart>) -> Builder<R, T>,
T: To<AuthorityEnd>,
{
self.inner.start_authority();
f(self.cast()).cast()
}
pub fn authority(
mut self,
authority: Authority<'_, R::UserinfoE, R::RegNameE>,
) -> Builder<R, AuthorityEnd> {
self.inner.push_authority(authority.cast());
self.cast::<AuthorityEnd>()
}
}
impl<R: RiMaybeRef, S: To<UserinfoEnd>> Builder<R, S> {
pub fn userinfo(mut self, userinfo: &EStr<R::UserinfoE>) -> Builder<R, UserinfoEnd> {
self.inner.push_userinfo(userinfo.as_str());
self.cast()
}
}
impl<R: RiMaybeRef, S: To<HostEnd>> Builder<R, S> {
pub fn host<'a>(
mut self,
host: impl AsHost<'a> + WithEncoder<R::RegNameE>,
) -> Builder<R, HostEnd> {
host.push_to(&mut self.inner);
self.cast()
}
}
impl<R, S: To<PortEnd>> Builder<R, S> {
pub fn port(mut self, port: impl AsPort) -> Builder<R, PortEnd> {
port.push_to(&mut self.inner.buf);
self.cast()
}
#[cfg(fluent_uri_unstable)]
pub fn port_with_default(self, port: u16, default: u16) -> Builder<R, PortEnd> {
if port != default {
self.cast()
} else {
self.port(port)
}
}
}
impl<R: RiMaybeRef, S: To<PathEnd>> Builder<R, S> {
pub fn path(mut self, path: &EStr<R::PathE>) -> Builder<R, PathEnd> {
self.inner.push_path(path.as_str());
self.cast()
}
}
impl<R: RiMaybeRef, S: To<QueryEnd>> Builder<R, S> {
pub fn query(mut self, query: &EStr<R::QueryE>) -> Builder<R, QueryEnd> {
self.inner.push_query(query.as_str());
self.cast()
}
}
impl<R: RiMaybeRef, S: To<FragmentEnd>> Builder<R, S> {
pub fn fragment(mut self, fragment: &EStr<R::FragmentE>) -> Builder<R, FragmentEnd> {
self.inner.push_fragment(fragment.as_str());
self.cast()
}
}
impl<R: RiMaybeRef<Val = String>, S: To<End>> Builder<R, S> {
pub fn build(self) -> Result<R, BuildError> {
self.inner
.validate()
.map(|()| R::new(self.inner.buf, self.inner.meta))
}
}