facti-api 0.2.0

Provides tools for interacting with Factorio REST APIs
use std::{fmt::Display, str::FromStr};

use serde::{Deserialize, Serialize};
use url::Url;

use crate::error::{ApiError, ApiErrorKind};

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Pagination {
    pub count: u32,
    pub links: PaginationLinks,
    pub page: u32,
    pub page_count: u32,
    pub page_size: u32,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PaginationLinks {
    pub first: Option<Url>,
    #[serde(rename = "prev")]
    pub previous: Option<Url>,

    pub next: Option<Url>,
    pub last: Option<Url>,
}

#[derive(Copy, Clone, Debug, Serialize)]
pub enum PageSize {
    #[serde(rename = "max")]
    Max,

    #[serde(untagged, serialize_with = "serialize_custom_page_size")]
    Custom(u32),
}

impl FromStr for PageSize {
    type Err = ApiError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s == "max" {
            Ok(PageSize::Max)
        } else {
            s.parse::<u32>().map(PageSize::Custom).map_err(|_| {
                ApiError::new(
                    ApiErrorKind::InvalidPageSize,
                    format!("{} is not a valid page size", s),
                    None,
                )
            })
        }
    }
}

impl Display for PageSize {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            PageSize::Max => f.write_str("max"),
            PageSize::Custom(size) => write!(f, "{}", size),
        }
    }
}

fn serialize_custom_page_size<S>(size: &u32, serializer: S) -> Result<S::Ok, S::Error>
where
    S: serde::Serializer,
{
    serializer.serialize_u32(*size)
}