add Cowy util trait
This commit is contained in:
parent
2fc015fb89
commit
0425bf2cf3
|
@ -3,6 +3,7 @@ use std::fmt;
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use crate::types::URIReference;
|
use crate::types::URIReference;
|
||||||
|
use crate::util::Cowy;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Document {
|
pub struct Document {
|
||||||
|
@ -42,7 +43,7 @@ impl Document {
|
||||||
self
|
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
|
where
|
||||||
U: TryInto<URIReference<'a>>,
|
U: TryInto<URIReference<'a>>,
|
||||||
{
|
{
|
||||||
|
@ -92,7 +93,7 @@ impl Document {
|
||||||
self
|
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 text = HeadingText::new_lossy(text);
|
||||||
let heading = Heading {
|
let heading = Heading {
|
||||||
level,
|
level,
|
||||||
|
@ -182,7 +183,7 @@ impl Text {
|
||||||
Self::default()
|
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))
|
Self(lossy_escaped_line(line, SPECIAL_STARTS))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,7 +196,7 @@ pub struct Link {
|
||||||
pub struct LinkLabel(String);
|
pub struct LinkLabel(String);
|
||||||
|
|
||||||
impl LinkLabel {
|
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);
|
let line = strip_newlines(line);
|
||||||
|
|
||||||
LinkLabel(line)
|
LinkLabel(line)
|
||||||
|
@ -210,7 +211,7 @@ pub struct Preformatted {
|
||||||
pub struct PreformattedText(String);
|
pub struct PreformattedText(String);
|
||||||
|
|
||||||
impl PreformattedText {
|
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]))
|
Self(lossy_escaped_line(line, &[PREFORMATTED_TOGGLE_START]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,7 +249,7 @@ impl Heading {
|
||||||
pub struct HeadingText(String);
|
pub struct HeadingText(String);
|
||||||
|
|
||||||
impl HeadingText {
|
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);
|
let line = strip_newlines(line);
|
||||||
|
|
||||||
Self(lossy_escaped_line(line, &[HEADING_START]))
|
Self(lossy_escaped_line(line, &[HEADING_START]))
|
||||||
|
@ -298,7 +299,7 @@ fn starts_with_any(s: &str, starts: &[&str]) -> bool {
|
||||||
false
|
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 line_ref = line.as_ref();
|
||||||
let contains_newline = line_ref.contains('\n');
|
let contains_newline = line_ref.contains('\n');
|
||||||
let has_special_start = starts_with_any(line_ref, escape_starts);
|
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
|
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'][..]) {
|
if !text.as_ref().contains(&['\r', '\n'][..]) {
|
||||||
return text.into();
|
return text.into();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use mime::Mime;
|
use crate::Mime;
|
||||||
|
use crate::util::Cowy;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug,Clone,PartialEq,Eq,Default)]
|
#[derive(Debug,Clone,PartialEq,Eq,Default)]
|
||||||
pub struct Meta(String);
|
pub struct Meta(String);
|
||||||
|
@ -9,7 +11,7 @@ impl Meta {
|
||||||
|
|
||||||
/// Creates a new "Meta" string.
|
/// Creates a new "Meta" string.
|
||||||
/// Fails if `meta` contains `\n`.
|
/// 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().contains("\n"), "Meta must not contain newlines");
|
||||||
ensure!(meta.as_ref().len() <= Self::MAX_LEN, "Meta must not exceed {} bytes", Self::MAX_LEN);
|
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:
|
/// Truncates `meta` to before:
|
||||||
/// - the first occurrence of `\n`
|
/// - the first occurrence of `\n`
|
||||||
/// - the character that makes `meta` exceed `Meta::MAX_LEN`
|
/// - 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 meta = meta.as_ref();
|
||||||
let truncate_pos = meta.char_indices().position(|(i, ch)| {
|
let truncate_pos = meta.char_indices().position(|(i, ch)| {
|
||||||
let is_newline = ch == '\n';
|
let is_newline = ch == '\n';
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use crate::types::{ResponseHeader, Body, Mime, Document};
|
use crate::types::{ResponseHeader, Body, Mime, Document};
|
||||||
|
use crate::util::Cowy;
|
||||||
use crate::GEMINI_MIME;
|
use crate::GEMINI_MIME;
|
||||||
|
|
||||||
pub struct Response {
|
pub struct Response {
|
||||||
|
@ -19,12 +20,12 @@ impl Response {
|
||||||
Self::success(&GEMINI_MIME).with_body(document)
|
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)?;
|
let header = ResponseHeader::input(prompt)?;
|
||||||
Ok(Self::new(header))
|
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);
|
let header = ResponseHeader::input_lossy(prompt);
|
||||||
Self::new(header)
|
Self::new(header)
|
||||||
}
|
}
|
||||||
|
@ -34,7 +35,7 @@ impl Response {
|
||||||
Self::new(header)
|
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)?;
|
let header = ResponseHeader::server_error(reason)?;
|
||||||
Ok(Self::new(header))
|
Ok(Self::new(header))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use mime::Mime;
|
use crate::Mime;
|
||||||
|
use crate::util::Cowy;
|
||||||
use crate::types::{Status, Meta};
|
use crate::types::{Status, Meta};
|
||||||
|
|
||||||
#[derive(Debug,Clone)]
|
#[derive(Debug,Clone)]
|
||||||
|
@ -9,14 +10,14 @@ pub struct ResponseHeader {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
Ok(Self {
|
||||||
status: Status::INPUT,
|
status: Status::INPUT,
|
||||||
meta: Meta::new(prompt).context("Invalid input prompt")?,
|
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 {
|
Self {
|
||||||
status: Status::INPUT,
|
status: Status::INPUT,
|
||||||
meta: Meta::new_lossy(prompt),
|
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 {
|
Ok(Self {
|
||||||
status: Status::PERMANENT_FAILURE,
|
status: Status::PERMANENT_FAILURE,
|
||||||
meta: Meta::new(reason).context("Invalid server error reason")?,
|
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 {
|
Self {
|
||||||
status: Status::PERMANENT_FAILURE,
|
status: Status::PERMANENT_FAILURE,
|
||||||
meta: Meta::new_lossy(reason),
|
meta: Meta::new_lossy(reason),
|
||||||
|
|
16
src/util.rs
16
src/util.rs
|
@ -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)
|
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,
|
||||||
|
{}
|
||||||
|
|
Loading…
Reference in New Issue