add Cowy util trait

This commit is contained in:
panicbit 2020-11-14 22:46:29 +01:00
parent 2fc015fb89
commit 0425bf2cf3
5 changed files with 40 additions and 19 deletions

View file

@ -3,6 +3,7 @@ use std::fmt;
use itertools::Itertools;
use crate::types::URIReference;
use crate::util::Cowy;
#[derive(Default)]
pub struct Document {
@ -42,7 +43,7 @@ impl Document {
self
}
pub fn add_link<'a, U>(&mut self, uri: U, label: impl AsRef<str> + Into<String>) -> &mut Self
pub fn add_link<'a, U>(&mut self, uri: U, label: impl Cowy<str>) -> &mut Self
where
U: TryInto<URIReference<'a>>,
{
@ -92,7 +93,7 @@ impl Document {
self
}
pub fn add_heading(&mut self, level: HeadingLevel, text: impl AsRef<str> + Into<String>) -> &mut Self {
pub fn add_heading(&mut self, level: HeadingLevel, text: impl Cowy<str>) -> &mut Self {
let text = HeadingText::new_lossy(text);
let heading = Heading {
level,
@ -182,7 +183,7 @@ impl Text {
Self::default()
}
pub fn new_lossy(line: impl AsRef<str> + Into<String>) -> Self {
pub fn new_lossy(line: impl Cowy<str>) -> Self {
Self(lossy_escaped_line(line, SPECIAL_STARTS))
}
}
@ -195,7 +196,7 @@ pub struct Link {
pub struct LinkLabel(String);
impl LinkLabel {
pub fn from_lossy(line: impl AsRef<str> + Into<String>) -> Self {
pub fn from_lossy(line: impl Cowy<str>) -> Self {
let line = strip_newlines(line);
LinkLabel(line)
@ -210,7 +211,7 @@ pub struct Preformatted {
pub struct PreformattedText(String);
impl PreformattedText {
pub fn new_lossy(line: impl AsRef<str> + Into<String>) -> Self {
pub fn new_lossy(line: impl Cowy<str>) -> Self {
Self(lossy_escaped_line(line, &[PREFORMATTED_TOGGLE_START]))
}
}
@ -248,7 +249,7 @@ impl Heading {
pub struct HeadingText(String);
impl HeadingText {
pub fn new_lossy(line: impl AsRef<str> + Into<String>) -> Self {
pub fn new_lossy(line: impl Cowy<str>) -> Self {
let line = strip_newlines(line);
Self(lossy_escaped_line(line, &[HEADING_START]))
@ -298,7 +299,7 @@ fn starts_with_any(s: &str, starts: &[&str]) -> bool {
false
}
fn lossy_escaped_line(line: impl AsRef<str> + Into<String>, escape_starts: &[&str]) -> String {
fn lossy_escaped_line(line: impl Cowy<str>, escape_starts: &[&str]) -> String {
let line_ref = line.as_ref();
let contains_newline = line_ref.contains('\n');
let has_special_start = starts_with_any(line_ref, escape_starts);
@ -320,7 +321,7 @@ fn lossy_escaped_line(line: impl AsRef<str> + Into<String>, escape_starts: &[&st
line
}
fn strip_newlines(text: impl AsRef<str> + Into<String>) -> String {
fn strip_newlines(text: impl Cowy<str>) -> String {
if !text.as_ref().contains(&['\r', '\n'][..]) {
return text.into();
}

View file

@ -1,5 +1,7 @@
use anyhow::*;
use mime::Mime;
use crate::Mime;
use crate::util::Cowy;
#[derive(Debug,Clone,PartialEq,Eq,Default)]
pub struct Meta(String);
@ -9,7 +11,7 @@ impl Meta {
/// Creates a new "Meta" string.
/// Fails if `meta` contains `\n`.
pub fn new(meta: impl AsRef<str> + Into<String>) -> Result<Self> {
pub fn new(meta: impl Cowy<str>) -> Result<Self> {
ensure!(!meta.as_ref().contains("\n"), "Meta must not contain newlines");
ensure!(meta.as_ref().len() <= Self::MAX_LEN, "Meta must not exceed {} bytes", Self::MAX_LEN);
@ -20,7 +22,7 @@ impl Meta {
/// Truncates `meta` to before:
/// - the first occurrence of `\n`
/// - the character that makes `meta` exceed `Meta::MAX_LEN`
pub fn new_lossy(meta: impl AsRef<str> + Into<String>) -> Self {
pub fn new_lossy(meta: impl Cowy<str>) -> Self {
let meta = meta.as_ref();
let truncate_pos = meta.char_indices().position(|(i, ch)| {
let is_newline = ch == '\n';

View file

@ -1,5 +1,6 @@
use anyhow::*;
use crate::types::{ResponseHeader, Body, Mime, Document};
use crate::util::Cowy;
use crate::GEMINI_MIME;
pub struct Response {
@ -19,12 +20,12 @@ impl Response {
Self::success(&GEMINI_MIME).with_body(document)
}
pub fn input(prompt: impl AsRef<str> + Into<String>) -> Result<Self> {
pub fn input(prompt: impl Cowy<str>) -> Result<Self> {
let header = ResponseHeader::input(prompt)?;
Ok(Self::new(header))
}
pub fn input_lossy(prompt: impl AsRef<str> + Into<String>) -> Self {
pub fn input_lossy(prompt: impl Cowy<str>) -> Self {
let header = ResponseHeader::input_lossy(prompt);
Self::new(header)
}
@ -34,7 +35,7 @@ impl Response {
Self::new(header)
}
pub fn server_error(reason: impl AsRef<str> + Into<String>) -> Result<Self> {
pub fn server_error(reason: impl Cowy<str>) -> Result<Self> {
let header = ResponseHeader::server_error(reason)?;
Ok(Self::new(header))
}

View file

@ -1,5 +1,6 @@
use anyhow::*;
use mime::Mime;
use crate::Mime;
use crate::util::Cowy;
use crate::types::{Status, Meta};
#[derive(Debug,Clone)]
@ -9,14 +10,14 @@ pub struct ResponseHeader {
}
impl ResponseHeader {
pub fn input(prompt: impl AsRef<str> + Into<String>) -> Result<Self> {
pub fn input(prompt: impl Cowy<str>) -> Result<Self> {
Ok(Self {
status: Status::INPUT,
meta: Meta::new(prompt).context("Invalid input prompt")?,
})
}
pub fn input_lossy(prompt: impl AsRef<str> + Into<String>) -> Self {
pub fn input_lossy(prompt: impl Cowy<str>) -> Self {
Self {
status: Status::INPUT,
meta: Meta::new_lossy(prompt),
@ -30,14 +31,14 @@ impl ResponseHeader {
}
}
pub fn server_error(reason: impl AsRef<str> + Into<String>) -> Result<Self> {
pub fn server_error(reason: impl Cowy<str>) -> Result<Self> {
Ok(Self {
status: Status::PERMANENT_FAILURE,
meta: Meta::new(reason).context("Invalid server error reason")?,
})
}
pub fn server_error_lossy(reason: impl AsRef<str> + Into<String>) -> Self {
pub fn server_error_lossy(reason: impl Cowy<str>) -> Self {
Self {
status: Status::PERMANENT_FAILURE,
meta: Meta::new_lossy(reason),

View file

@ -102,3 +102,19 @@ pub fn guess_mime_from_path<P: AsRef<Path>>(path: P) -> Mime {
mime.parse::<Mime>().unwrap_or(mime::APPLICATION_OCTET_STREAM)
}
/// A convenience trait alias for `AsRef<T> + Into<T::Owned>`,
/// most commonly used to accept `&str` or `String`:
///
/// `Cowy<str>` ⇔ `AsRef<str> + Into<String>`
pub trait Cowy<T>
where
Self: AsRef<T> + Into<T::Owned>,
T: ToOwned + ?Sized,
{}
impl<C, T> Cowy<T> for C
where
C: AsRef<T> + Into<T::Owned>,
T: ToOwned + ?Sized,
{}