1use std::str::FromStr;
22
23#[cfg(feature = "diagnostics")]
24use miette::Diagnostic;
25
26#[cfg(feature = "serde")]
27use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
28
29use thiserror::Error;
30
31#[derive(Debug, Error)]
33#[error("unknown method `{unknown}`")]
34#[cfg_attr(
35 feature = "diagnostics",
36 derive(Diagnostic),
37 diagnostic(
38 code(pkce_std::method),
39 help("expected either `{PLAIN}` (discouraged) or `{SHA256}` (recommended)")
40 )
41)]
42pub struct Error {
43 pub unknown: String,
45}
46
47impl Error {
48 pub const fn new(unknown: String) -> Self {
50 Self { unknown }
51 }
52}
53
54pub const PLAIN: &str = "plain";
56
57pub const SHA256: &str = "S256";
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
62pub enum Method {
63 Plain,
65 #[default]
67 Sha256,
68}
69
70#[cfg(feature = "serde")]
71impl Serialize for Method {
72 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
73 self.static_str().serialize(serializer)
74 }
75}
76
77#[cfg(feature = "serde")]
78impl<'de> Deserialize<'de> for Method {
79 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
80 let string = <&str>::deserialize(deserializer)?;
81
82 string.parse().map_err(de::Error::custom)
83 }
84}
85
86type StaticStr = &'static str;
87
88impl Method {
89 pub const fn static_str(&self) -> StaticStr {
91 match self {
92 Self::Plain => PLAIN,
93 Self::Sha256 => SHA256,
94 }
95 }
96}
97
98impl FromStr for Method {
99 type Err = Error;
100
101 fn from_str(string: &str) -> Result<Self, Self::Err> {
102 match string {
103 PLAIN => Ok(Self::Plain),
104 SHA256 => Ok(Self::Sha256),
105 _ => Err(Self::Err::new(string.to_owned())),
106 }
107 }
108}