oxinat_core/uri/
builder.rs

1use std::fmt::Display;
2
3use thiserror::Error;
4
5pub type BuildResult = anyhow::Result<String>;
6
7#[derive(Debug, Error)]
8pub enum UriBuildError {
9    #[error("pattern could not be determined from arguments")]
10    UnrecognizedPattern,
11    #[error("attempted to build an invalid URI path")]
12    Validation
13}
14
15/// Type is able to construct a URI usable for
16/// making REST calls.
17pub trait UriBuilder: Display {
18    /// Build the resulting URI from this builder.
19    fn build(&self) -> BuildResult;
20    /// Build the resulting URI with an additional
21    /// component appended at the end.
22    #[inline]
23    fn build_join<UB: UriBuilder>(&self, other: UB) -> BuildResult {
24        Ok([self.build()?, other.build()?].join("/"))
25    }
26    /// Build the resulting URI with an additional
27    /// component appended at the end, otherwise
28    /// returns an error if the predicate isn't
29    /// met.
30    #[inline]
31    fn build_join_if<UB: UriBuilder>(&self, other: UB, predicate: fn(&Self) -> bool) -> BuildResult {
32        predicate(self)
33            .then(|| self.build_join(other))
34            .or_else(|| Err(UriBuildError::UnrecognizedPattern.into()).into())
35            .unwrap()
36    }
37}
38
39impl UriBuilder for str {
40    fn build(&self) -> crate::BuildResult {
41        Ok(self.to_string())
42    }
43}
44
45impl<T> UriBuilder for T
46where
47    T: Display + AsRef<str>
48{
49    fn build(&self) -> BuildResult {
50        Ok(self.as_ref().to_owned())
51    }
52}