use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use tokio_util::sync::CancellationToken;
use ts_rs::TS;
pub use crate::types::Warning;
pub type SharedHeaders = HashMap<String, String>;
pub type SharedProviderOptions = HashMap<String, Value>;
pub type SharedProviderMetadata = HashMap<String, Value>;
pub type SharedProviderReference = HashMap<String, String>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, TS)]
#[ts(export)]
pub enum FileBytes {
Binary(Vec<u8>),
Base64(String),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, TS)]
#[ts(export)]
pub enum FileData {
Data { data: FileBytes },
Url { url: String },
Reference { reference: SharedProviderReference },
Text { text: String },
}
#[derive(Debug, Clone)]
pub struct AbortSignal {
token: CancellationToken,
}
impl Default for AbortSignal {
fn default() -> Self {
Self::new()
}
}
impl AbortSignal {
pub fn new() -> Self {
Self {
token: CancellationToken::new(),
}
}
pub fn abort(&self) {
self.token.cancel();
}
pub fn is_aborted(&self) -> bool {
self.token.is_cancelled()
}
pub fn cancelled(&self) -> impl std::future::Future<Output = ()> + Send + 'static {
let token = self.token.clone();
async move { token.cancelled_owned().await }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TS)]
#[ts(export)]
pub struct Size {
width: u32,
height: u32,
}
impl Size {
pub const fn new(width: u32, height: u32) -> Self {
Self { width, height }
}
pub fn parse(s: &str) -> Result<Self, String> {
let (w, h) = parse_pair(s, 'x').ok_or_else(|| {
format!("invalid size `{s}`: expected format `{{width}}x{{height}}` (e.g. `1024x1024`)")
})?;
if w == 0 || h == 0 {
return Err(format!("invalid size `{s}`: width and height must be > 0"));
}
Ok(Self::new(w, h))
}
pub const fn width(&self) -> u32 {
self.width
}
pub const fn height(&self) -> u32 {
self.height
}
}
impl std::fmt::Display for Size {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}x{}", self.width, self.height)
}
}
impl std::str::FromStr for Size {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse(s)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TS)]
#[ts(export)]
pub struct AspectRatio {
width: u32,
height: u32,
}
impl AspectRatio {
pub const fn new(width: u32, height: u32) -> Self {
Self { width, height }
}
pub fn parse(s: &str) -> Result<Self, String> {
let (w, h) = parse_pair(s, ':').ok_or_else(|| {
format!(
"invalid aspect ratio `{s}`: expected format `{{width}}:{{height}}` (e.g. `16:9`)"
)
})?;
if w == 0 || h == 0 {
return Err(format!(
"invalid aspect ratio `{s}`: width and height must be > 0"
));
}
Ok(Self::new(w, h))
}
pub const fn width(&self) -> u32 {
self.width
}
pub const fn height(&self) -> u32 {
self.height
}
}
impl std::fmt::Display for AspectRatio {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.width, self.height)
}
}
impl std::str::FromStr for AspectRatio {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse(s)
}
}
fn parse_pair(s: &str, sep: char) -> Option<(u32, u32)> {
let (a, b) = s.split_once(sep)?;
let a: u32 = a.trim().parse().ok()?;
let b: u32 = b.trim().parse().ok()?;
Some((a, b))
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[ts(export)]
pub struct ResponseInfo {
pub timestamp: Option<String>,
pub model_id: Option<String>,
pub headers: Option<SharedHeaders>,
pub body: Option<Value>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[ts(export)]
pub struct RequestInfo {
pub body: Option<Value>,
}