1use std::{fmt, str::FromStr};
4
5use const_macros::const_none;
6
7use miette::Diagnostic;
8
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11
12use thiserror::Error;
13
14use crate::{
15 int::{self, ParseError},
16 macros::errors,
17};
18
19pub const DEFAULT: u64 = 0;
21
22#[derive(Debug, Error, Diagnostic)]
24#[error("failed to parse `{string}` to counter")]
25#[diagnostic(code(otp_std::counter), help("see the report for more information"))]
26pub struct Error {
27 #[source]
29 #[diagnostic_source]
30 pub source: ParseError,
31 pub string: String,
33}
34
35impl Error {
36 pub const fn new(source: ParseError, string: String) -> Self {
38 Self { source, string }
39 }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
44#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
45#[cfg_attr(feature = "serde", serde(from = "u64", into = "u64"))]
46pub struct Counter {
47 value: u64,
48}
49
50errors! {
51 Type = Error,
52 Hack = $,
53 error => new(error, string => to_owned),
54}
55
56impl FromStr for Counter {
57 type Err = Error;
58
59 fn from_str(string: &str) -> Result<Self, Self::Err> {
60 let value = string
61 .parse()
62 .map_err(|error| error!(int::wrap(error), string))?;
63
64 Ok(Self::new(value))
65 }
66}
67
68impl fmt::Display for Counter {
69 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
70 self.get().fmt(formatter)
71 }
72}
73
74impl From<u64> for Counter {
75 fn from(value: u64) -> Self {
76 Self::new(value)
77 }
78}
79
80impl From<Counter> for u64 {
81 fn from(counter: Counter) -> Self {
82 counter.get()
83 }
84}
85
86impl Default for Counter {
87 fn default() -> Self {
88 Self::DEFAULT
89 }
90}
91
92pub const OVERFLOW: &str = "overflow";
94
95impl Counter {
96 pub const fn new(value: u64) -> Self {
98 Self { value }
99 }
100
101 pub const fn get(self) -> u64 {
103 self.value
104 }
105
106 #[must_use = "this method returns the incremented counter instead of modifying the original"]
134 pub const fn try_next(self) -> Option<Self> {
135 let value = const_none!(self.get().checked_add(1));
136
137 Some(Self::new(value))
138 }
139
140 #[must_use = "this method returns the incremented counter instead of modifying the original"]
167 pub const fn next(self) -> Self {
168 self.try_next().expect(OVERFLOW)
169 }
170
171 pub const DEFAULT: Self = Self::new(DEFAULT);
173}