parent
d9fc959738
commit
745a3a61d5
@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
pub trait JoinStrsExt: Sized
|
||||||
|
{
|
||||||
|
/// Join an iterator of `str` with a seperator
|
||||||
|
fn join(self, with: &str) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T,I> JoinStrsExt for I
|
||||||
|
where I: Iterator<Item=T>,
|
||||||
|
T: AsRef<str>
|
||||||
|
{
|
||||||
|
fn join(self, with: &str) -> String
|
||||||
|
{
|
||||||
|
let mut output = String::new();
|
||||||
|
let mut first=true;
|
||||||
|
for string in self
|
||||||
|
{
|
||||||
|
if !first {
|
||||||
|
output.push_str(with);
|
||||||
|
}
|
||||||
|
let string = string.as_ref();
|
||||||
|
output.push_str(string);
|
||||||
|
first=false;
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +0,0 @@
|
|||||||
use super::*;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Loli
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,55 @@
|
|||||||
|
use super::*;
|
||||||
|
use std::{
|
||||||
|
str,
|
||||||
|
io::{
|
||||||
|
self,
|
||||||
|
Write,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const HEADER_BASE64_JPEG: &'static str = "/9j/";
|
||||||
|
const HEADER_BASE64_PNG: &'static str = "iVBO";
|
||||||
|
const HEADER_BASE64_GIF: &'static str = "R0lG";
|
||||||
|
|
||||||
|
/// An image type header
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ImageType
|
||||||
|
{
|
||||||
|
Png,
|
||||||
|
Jpeg,
|
||||||
|
Gif,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ImageType
|
||||||
|
{
|
||||||
|
fn default() -> Self
|
||||||
|
{
|
||||||
|
Self::Jpeg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl str::FromStr for ImageType
|
||||||
|
{
|
||||||
|
type Err = error::Error;
|
||||||
|
|
||||||
|
/// Determine image type from base64
|
||||||
|
fn from_str(from: &str) -> Result<Self, Self::Err>
|
||||||
|
{
|
||||||
|
if from.len() > 4 {
|
||||||
|
Ok(match &from[..4] {
|
||||||
|
HEADER_BASE64_GIF => Self::Gif,
|
||||||
|
HEADER_BASE64_PNG => Self::Png,
|
||||||
|
HEADER_BASE64_JPEG => Self::Jpeg,
|
||||||
|
_ => return Err(error::Error::UnknownFormat),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(error::Error::InvalidFormat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate the required data size from base64 input size
|
||||||
|
pub const fn data_size(base64: usize) -> usize
|
||||||
|
{
|
||||||
|
((4 * base64 / 3) + 3) & !3
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
use super::*;
|
||||||
|
use std::{
|
||||||
|
error,
|
||||||
|
fmt,
|
||||||
|
io,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error
|
||||||
|
{
|
||||||
|
/// Image format could not be determined.
|
||||||
|
UnknownFormat,
|
||||||
|
/// Image is not valid
|
||||||
|
InvalidFormat,
|
||||||
|
/// Image decode failedb
|
||||||
|
DecodeError,
|
||||||
|
|
||||||
|
// Internals
|
||||||
|
/// IO error
|
||||||
|
IO(io::Error),
|
||||||
|
/// Failed to format text
|
||||||
|
Formatter(fmt::Error),
|
||||||
|
/// Something bad
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl error::Error for Error
|
||||||
|
{
|
||||||
|
fn source(&self) -> Option<&(dyn error::Error + 'static)>
|
||||||
|
{
|
||||||
|
Some(match &self {
|
||||||
|
Self::IO(io) => io,
|
||||||
|
Self::Formatter(fmt) => fmt,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
write!(f, "loli module: ")?;
|
||||||
|
match self {
|
||||||
|
Self::UnknownFormat => write!(f, "could not determine image format"),
|
||||||
|
Self::InvalidFormat => write!(f, "image is not valid"),
|
||||||
|
Self::DecodeError => write!(f, "image decode failed"),
|
||||||
|
Self::IO(io) => write!(f, "io: {}", io),
|
||||||
|
Self::Formatter(fmt) => write!(f, "formatting: {}", fmt),
|
||||||
|
_ => write!(f, "unknown error"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for Error
|
||||||
|
{
|
||||||
|
fn from(er: io::Error) -> Self
|
||||||
|
{
|
||||||
|
Self::IO(er)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<fmt::Error> for Error
|
||||||
|
{
|
||||||
|
fn from(er: fmt::Error) -> Self
|
||||||
|
{
|
||||||
|
Self::Formatter(er)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<base64::DecodeError> for Error
|
||||||
|
{
|
||||||
|
fn from(_er: base64::DecodeError) -> Self
|
||||||
|
{
|
||||||
|
Self::DecodeError
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
pub mod error;
|
||||||
|
pub mod encoding;
|
||||||
|
|
||||||
|
/// Attempt to decode an image
|
||||||
|
pub fn decode<S, W>(input: S, mut output: W) -> Result<usize, error::Error>
|
||||||
|
where S: AsRef<[u8]>,
|
||||||
|
W: AsMut<[u8]>
|
||||||
|
{
|
||||||
|
let input_bytes = input.as_ref();
|
||||||
|
let output_bytes = output.as_mut();
|
||||||
|
|
||||||
|
Ok(base64::decode_config_slice(input_bytes, base64::STANDARD, output_bytes)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate the size for a base64 inpue
|
||||||
|
pub fn calc_size<T>(input: T) -> usize
|
||||||
|
where T: AsRef<[u8]>
|
||||||
|
{
|
||||||
|
encoding::data_size(input.as_ref().len())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to get the image format from a `str` slice.
|
||||||
|
pub fn attempt_get_format<T>(input: T) -> Result<encoding::ImageType, error::Error>
|
||||||
|
where T: AsRef<str>
|
||||||
|
{
|
||||||
|
input.as_ref().parse()
|
||||||
|
}
|
Loading…
Reference in new issue