use std::{fmt, num::ParseIntError, str::FromStr};
use const_macros::{const_early, const_ok, const_try};
#[cfg(feature = "diagnostics")]
use miette::Diagnostic;
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
use thiserror::Error;
use crate::{encoding, length::Length};
pub const MIN: usize = 32;
pub const DEFAULT: usize = 64;
pub const MAX: usize = 96;
#[derive(Debug, Error)]
#[error("unexpected count `{value}`; expected in range `[{MIN}, {MAX}]`")]
pub struct Error {
pub value: usize,
}
impl Error {
pub const fn new(value: usize) -> Self {
Self { value }
}
}
#[derive(Debug, Error)]
#[cfg_attr(feature = "diagnostics", derive(Diagnostic))]
pub enum ParseError {
#[error("invalid count")]
#[cfg_attr(
feature = "diagnostics",
diagnostic(
code(pkce_std::count::parse),
help("make sure the count is in the valid range")
)
)]
Length(#[from] Error),
#[error("parse integer error")]
#[cfg_attr(
feature = "diagnostics",
diagnostic(code(pkce_std::count::parse::int), help("check the string"))
)]
Int(#[from] ParseIntError),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Count {
value: usize,
}
#[cfg(feature = "serde")]
impl Serialize for Count {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.get().serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Count {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let value = usize::deserialize(deserializer)?;
Self::new(value).map_err(de::Error::custom)
}
}
impl TryFrom<usize> for Count {
type Error = Error;
fn try_from(value: usize) -> Result<Self, Self::Error> {
Self::new(value)
}
}
impl From<Count> for usize {
fn from(count: Count) -> Self {
count.get()
}
}
impl From<Count> for Length {
fn from(count: Count) -> Self {
unsafe { Self::new_unchecked(count.encoded()) }
}
}
impl fmt::Display for Count {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
self.get().fmt(formatter)
}
}
impl Default for Count {
fn default() -> Self {
Self::DEFAULT
}
}
impl FromStr for Count {
type Err = ParseError;
fn from_str(string: &str) -> Result<Self, Self::Err> {
let value = string.parse()?;
let count = Self::new(value)?;
Ok(count)
}
}
impl Count {
pub const fn new(value: usize) -> Result<Self, Error> {
const_try!(Self::check(value));
Ok(unsafe { Self::new_unchecked(value) })
}
pub const fn new_ok(value: usize) -> Option<Self> {
const_ok!(Self::new(value))
}
pub const fn check(value: usize) -> Result<(), Error> {
const_early!(value < MIN || value > MAX => Error::new(value));
Ok(())
}
pub const unsafe fn new_unchecked(value: usize) -> Self {
Self { value }
}
pub const fn get(self) -> usize {
self.value
}
pub const fn encoded(self) -> usize {
encoding::length(self.get())
}
pub const MIN: Self = Self::new_ok(MIN).unwrap();
pub const DEFAULT: Self = Self::new_ok(DEFAULT).unwrap();
pub const MAX: Self = Self::new_ok(MAX).unwrap();
}