Skip to main content

auth_framework/
types.rs

1//! Common domain types used throughout the AuthFramework.
2//!
3//! This module provides type-safe wrappers around raw collections and primitives
4//! to improve API clarity and prevent common mistakes.
5
6use std::collections::HashMap;
7use std::ops::Deref;
8
9/// A collection of user roles.
10///
11/// Provides type safety when working with role assignments and prevents
12/// accidentally passing the wrong collection type.
13///
14/// # Examples
15///
16/// ```rust
17/// use auth_framework::types::Roles;
18///
19/// let roles = Roles(vec!["admin".to_string(), "user".to_string()]);
20/// assert_eq!(roles.len(), 2);
21/// ```
22#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
23pub struct Roles(pub Vec<String>);
24
25impl Roles {
26    /// Create a new Roles collection
27    pub fn new(roles: Vec<String>) -> Self {
28        Self(roles)
29    }
30
31    /// Create an empty Roles collection
32    pub fn empty() -> Self {
33        Self(Vec::new())
34    }
35
36    /// Get the number of roles
37    pub fn len(&self) -> usize {
38        self.0.len()
39    }
40
41    /// Check if the collection is empty
42    pub fn is_empty(&self) -> bool {
43        self.0.is_empty()
44    }
45
46    /// Check if a specific role is present
47    pub fn contains(&self, role: &str) -> bool {
48        self.0.contains(&role.to_string())
49    }
50
51    /// Add a role to the collection
52    pub fn push(&mut self, role: String) {
53        self.0.push(role);
54    }
55
56    /// Iterate over the roles
57    pub fn iter(&self) -> std::slice::Iter<'_, String> {
58        self.0.iter()
59    }
60}
61
62impl Default for Roles {
63    fn default() -> Self {
64        Self::empty()
65    }
66}
67
68impl From<Vec<String>> for Roles {
69    fn from(roles: Vec<String>) -> Self {
70        Self(roles)
71    }
72}
73
74impl From<Roles> for Vec<String> {
75    fn from(roles: Roles) -> Vec<String> {
76        roles.0
77    }
78}
79
80impl<S: AsRef<str>> From<&[S]> for Roles {
81    fn from(slice: &[S]) -> Self {
82        Self(slice.iter().map(|s| s.as_ref().to_owned()).collect())
83    }
84}
85
86impl Deref for Roles {
87    type Target = Vec<String>;
88    fn deref(&self) -> &Self::Target {
89        &self.0
90    }
91}
92
93impl std::ops::DerefMut for Roles {
94    fn deref_mut(&mut self) -> &mut Self::Target {
95        &mut self.0
96    }
97}
98
99impl FromIterator<String> for Roles {
100    fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {
101        Self(iter.into_iter().collect())
102    }
103}
104
105impl IntoIterator for Roles {
106    type Item = String;
107    type IntoIter = std::vec::IntoIter<String>;
108    fn into_iter(self) -> Self::IntoIter {
109        self.0.into_iter()
110    }
111}
112
113impl<'a> IntoIterator for &'a Roles {
114    type Item = &'a String;
115    type IntoIter = std::slice::Iter<'a, String>;
116    fn into_iter(self) -> Self::IntoIter {
117        self.0.iter()
118    }
119}
120
121#[cfg(feature = "postgres-storage")]
122impl sqlx::Type<sqlx::Postgres> for Roles {
123    fn type_info() -> sqlx::postgres::PgTypeInfo {
124        <Vec<String> as sqlx::Type<sqlx::Postgres>>::type_info()
125    }
126    fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {
127        <Vec<String> as sqlx::Type<sqlx::Postgres>>::compatible(ty)
128    }
129}
130
131#[cfg(feature = "postgres-storage")]
132impl<'r> sqlx::Decode<'r, sqlx::Postgres> for Roles {
133    fn decode(value: sqlx::postgres::PgValueRef<'r>) -> Result<Self, sqlx::error::BoxDynError> {
134        let inner = <Vec<String> as sqlx::Decode<'r, sqlx::Postgres>>::decode(value)?;
135        Ok(Self(inner))
136    }
137}
138
139#[cfg(feature = "postgres-storage")]
140impl<'q> sqlx::Encode<'q, sqlx::Postgres> for Roles {
141    fn encode_by_ref(
142        &self,
143        buf: &mut sqlx::postgres::PgArgumentBuffer,
144    ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
145        <Vec<String> as sqlx::Encode<'q, sqlx::Postgres>>::encode_by_ref(&self.0, buf)
146    }
147}
148
149/// A collection of OAuth scopes.
150///
151/// Provides type safety for scope management and prevents confusion
152/// with other string collections.
153///
154/// # Examples
155///
156/// ```rust
157/// use auth_framework::types::Scopes;
158///
159/// let scopes = Scopes(vec!["read".to_string(), "write".to_string()]);
160/// assert!(scopes.contains("read"));
161/// ```
162#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
163pub struct Scopes(pub Vec<String>);
164
165impl Scopes {
166    /// Create a new Scopes collection
167    pub fn new(scopes: Vec<String>) -> Self {
168        Self(scopes)
169    }
170
171    /// Create an empty Scopes collection
172    pub fn empty() -> Self {
173        Self(Vec::new())
174    }
175
176    /// Get the number of scopes
177    pub fn len(&self) -> usize {
178        self.0.len()
179    }
180
181    /// Check if the collection is empty
182    pub fn is_empty(&self) -> bool {
183        self.0.is_empty()
184    }
185
186    /// Check if a specific scope is present
187    pub fn contains(&self, scope: &str) -> bool {
188        self.0.contains(&scope.to_string())
189    }
190
191    /// Add a scope to the collection
192    pub fn push(&mut self, scope: String) {
193        self.0.push(scope);
194    }
195
196    /// Iterate over the scopes
197    pub fn iter(&self) -> std::slice::Iter<'_, String> {
198        self.0.iter()
199    }
200}
201
202impl Default for Scopes {
203    fn default() -> Self {
204        Self::empty()
205    }
206}
207
208impl From<Vec<String>> for Scopes {
209    fn from(scopes: Vec<String>) -> Self {
210        Self(scopes)
211    }
212}
213
214impl From<Scopes> for Vec<String> {
215    fn from(scopes: Scopes) -> Vec<String> {
216        scopes.0
217    }
218}
219
220impl<S: AsRef<str>> From<&[S]> for Scopes {
221    fn from(slice: &[S]) -> Self {
222        Self(slice.iter().map(|s| s.as_ref().to_owned()).collect())
223    }
224}
225
226impl Deref for Scopes {
227    type Target = Vec<String>;
228    fn deref(&self) -> &Self::Target {
229        &self.0
230    }
231}
232
233impl std::ops::DerefMut for Scopes {
234    fn deref_mut(&mut self) -> &mut Self::Target {
235        &mut self.0
236    }
237}
238
239impl FromIterator<String> for Scopes {
240    fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {
241        Self(iter.into_iter().collect())
242    }
243}
244
245impl IntoIterator for Scopes {
246    type Item = String;
247    type IntoIter = std::vec::IntoIter<String>;
248    fn into_iter(self) -> Self::IntoIter {
249        self.0.into_iter()
250    }
251}
252
253impl<'a> IntoIterator for &'a Scopes {
254    type Item = &'a String;
255    type IntoIter = std::slice::Iter<'a, String>;
256    fn into_iter(self) -> Self::IntoIter {
257        self.0.iter()
258    }
259}
260
261#[cfg(feature = "postgres-storage")]
262impl sqlx::Type<sqlx::Postgres> for Scopes {
263    fn type_info() -> sqlx::postgres::PgTypeInfo {
264        <Vec<String> as sqlx::Type<sqlx::Postgres>>::type_info()
265    }
266    fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {
267        <Vec<String> as sqlx::Type<sqlx::Postgres>>::compatible(ty)
268    }
269}
270
271#[cfg(feature = "postgres-storage")]
272impl<'r> sqlx::Decode<'r, sqlx::Postgres> for Scopes {
273    fn decode(value: sqlx::postgres::PgValueRef<'r>) -> Result<Self, sqlx::error::BoxDynError> {
274        let inner = <Vec<String> as sqlx::Decode<'r, sqlx::Postgres>>::decode(value)?;
275        Ok(Self(inner))
276    }
277}
278
279#[cfg(feature = "postgres-storage")]
280impl<'q> sqlx::Encode<'q, sqlx::Postgres> for Scopes {
281    fn encode_by_ref(
282        &self,
283        buf: &mut sqlx::postgres::PgArgumentBuffer,
284    ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
285        <Vec<String> as sqlx::Encode<'q, sqlx::Postgres>>::encode_by_ref(&self.0, buf)
286    }
287}
288
289/// A collection of redirect URIs for OAuth clients.
290///
291/// Provides type safety for redirect URI management.
292///
293/// # Examples
294///
295/// ```rust
296/// use auth_framework::types::RedirectUris;
297///
298/// let uris = RedirectUris(vec!["https://example.com/callback".to_string()]);
299/// assert!(uris.contains("https://example.com/callback"));
300/// ```
301#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
302pub struct RedirectUris(pub Vec<String>);
303
304impl RedirectUris {
305    /// Create a new RedirectUris collection
306    pub fn new(uris: Vec<String>) -> Self {
307        Self(uris)
308    }
309
310    /// Create an empty RedirectUris collection
311    pub fn empty() -> Self {
312        Self(Vec::new())
313    }
314
315    /// Get the number of URIs
316    pub fn len(&self) -> usize {
317        self.0.len()
318    }
319
320    /// Check if the collection is empty
321    pub fn is_empty(&self) -> bool {
322        self.0.is_empty()
323    }
324
325    /// Check if a specific URI is present
326    pub fn contains(&self, uri: &str) -> bool {
327        self.0.contains(&uri.to_string())
328    }
329
330    /// Add a URI to the collection
331    pub fn push(&mut self, uri: String) {
332        self.0.push(uri);
333    }
334
335    /// Iterate over the URIs
336    pub fn iter(&self) -> std::slice::Iter<'_, String> {
337        self.0.iter()
338    }
339}
340
341impl Default for RedirectUris {
342    fn default() -> Self {
343        Self::empty()
344    }
345}
346
347impl From<Vec<String>> for RedirectUris {
348    fn from(uris: Vec<String>) -> Self {
349        Self(uris)
350    }
351}
352
353impl From<RedirectUris> for Vec<String> {
354    fn from(uris: RedirectUris) -> Vec<String> {
355        uris.0
356    }
357}
358
359impl<S: AsRef<str>> From<&[S]> for RedirectUris {
360    fn from(slice: &[S]) -> Self {
361        Self(slice.iter().map(|s| s.as_ref().to_owned()).collect())
362    }
363}
364
365impl Deref for RedirectUris {
366    type Target = Vec<String>;
367    fn deref(&self) -> &Self::Target {
368        &self.0
369    }
370}
371
372impl std::ops::DerefMut for RedirectUris {
373    fn deref_mut(&mut self) -> &mut Self::Target {
374        &mut self.0
375    }
376}
377
378impl FromIterator<String> for RedirectUris {
379    fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {
380        Self(iter.into_iter().collect())
381    }
382}
383
384impl IntoIterator for RedirectUris {
385    type Item = String;
386    type IntoIter = std::vec::IntoIter<String>;
387    fn into_iter(self) -> Self::IntoIter {
388        self.0.into_iter()
389    }
390}
391
392impl<'a> IntoIterator for &'a RedirectUris {
393    type Item = &'a String;
394    type IntoIter = std::slice::Iter<'a, String>;
395    fn into_iter(self) -> Self::IntoIter {
396        self.0.iter()
397    }
398}
399
400/// A collection of OAuth grant types.
401///
402/// Provides type safety for grant type management.
403///
404/// # Examples
405///
406/// ```rust
407/// use auth_framework::types::GrantTypes;
408///
409/// let types = GrantTypes(vec!["authorization_code".to_string()]);
410/// assert!(types.contains("authorization_code"));
411/// ```
412#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
413pub struct GrantTypes(pub Vec<String>);
414
415impl GrantTypes {
416    /// Create a new GrantTypes collection
417    pub fn new(types: Vec<String>) -> Self {
418        Self(types)
419    }
420
421    /// Create an empty GrantTypes collection
422    pub fn empty() -> Self {
423        Self(Vec::new())
424    }
425
426    /// Get the number of types
427    pub fn len(&self) -> usize {
428        self.0.len()
429    }
430
431    /// Check if the collection is empty
432    pub fn is_empty(&self) -> bool {
433        self.0.is_empty()
434    }
435
436    /// Check if a specific type is present
437    pub fn contains(&self, grant_type: &str) -> bool {
438        self.0.contains(&grant_type.to_string())
439    }
440
441    /// Add a type to the collection
442    pub fn push(&mut self, grant_type: String) {
443        self.0.push(grant_type);
444    }
445
446    /// Iterate over the types
447    pub fn iter(&self) -> std::slice::Iter<'_, String> {
448        self.0.iter()
449    }
450}
451
452impl Default for GrantTypes {
453    fn default() -> Self {
454        Self::empty()
455    }
456}
457
458impl From<Vec<String>> for GrantTypes {
459    fn from(types: Vec<String>) -> Self {
460        Self(types)
461    }
462}
463
464impl From<GrantTypes> for Vec<String> {
465    fn from(types: GrantTypes) -> Vec<String> {
466        types.0
467    }
468}
469
470impl<S: AsRef<str>> From<&[S]> for GrantTypes {
471    fn from(slice: &[S]) -> Self {
472        Self(slice.iter().map(|s| s.as_ref().to_owned()).collect())
473    }
474}
475
476impl Deref for GrantTypes {
477    type Target = Vec<String>;
478    fn deref(&self) -> &Self::Target {
479        &self.0
480    }
481}
482
483impl std::ops::DerefMut for GrantTypes {
484    fn deref_mut(&mut self) -> &mut Self::Target {
485        &mut self.0
486    }
487}
488
489impl FromIterator<String> for GrantTypes {
490    fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {
491        Self(iter.into_iter().collect())
492    }
493}
494
495impl IntoIterator for GrantTypes {
496    type Item = String;
497    type IntoIter = std::vec::IntoIter<String>;
498    fn into_iter(self) -> Self::IntoIter {
499        self.0.into_iter()
500    }
501}
502
503impl<'a> IntoIterator for &'a GrantTypes {
504    type Item = &'a String;
505    type IntoIter = std::slice::Iter<'a, String>;
506    fn into_iter(self) -> Self::IntoIter {
507        self.0.iter()
508    }
509}
510
511/// A collection of OAuth response types.
512///
513/// Provides type safety for response type management.
514///
515/// # Examples
516///
517/// ```rust
518/// use auth_framework::types::ResponseTypes;
519///
520/// let types = ResponseTypes(vec!["code".to_string()]);
521/// assert!(types.contains("code"));
522/// ```
523#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
524pub struct ResponseTypes(pub Vec<String>);
525
526impl ResponseTypes {
527    /// Create a new ResponseTypes collection
528    pub fn new(types: Vec<String>) -> Self {
529        Self(types)
530    }
531
532    /// Create an empty ResponseTypes collection
533    pub fn empty() -> Self {
534        Self(Vec::new())
535    }
536
537    /// Get the number of types
538    pub fn len(&self) -> usize {
539        self.0.len()
540    }
541
542    /// Check if the collection is empty
543    pub fn is_empty(&self) -> bool {
544        self.0.is_empty()
545    }
546
547    /// Check if a specific type is present
548    pub fn contains(&self, response_type: &str) -> bool {
549        self.0.contains(&response_type.to_string())
550    }
551
552    /// Add a type to the collection
553    pub fn push(&mut self, response_type: String) {
554        self.0.push(response_type);
555    }
556
557    /// Iterate over the types
558    pub fn iter(&self) -> std::slice::Iter<'_, String> {
559        self.0.iter()
560    }
561}
562
563impl Default for ResponseTypes {
564    fn default() -> Self {
565        Self::empty()
566    }
567}
568
569impl From<Vec<String>> for ResponseTypes {
570    fn from(types: Vec<String>) -> Self {
571        Self(types)
572    }
573}
574
575impl From<ResponseTypes> for Vec<String> {
576    fn from(types: ResponseTypes) -> Vec<String> {
577        types.0
578    }
579}
580
581impl<S: AsRef<str>> From<&[S]> for ResponseTypes {
582    fn from(slice: &[S]) -> Self {
583        Self(slice.iter().map(|s| s.as_ref().to_owned()).collect())
584    }
585}
586
587impl Deref for ResponseTypes {
588    type Target = Vec<String>;
589    fn deref(&self) -> &Self::Target {
590        &self.0
591    }
592}
593
594impl std::ops::DerefMut for ResponseTypes {
595    fn deref_mut(&mut self) -> &mut Self::Target {
596        &mut self.0
597    }
598}
599
600impl FromIterator<String> for ResponseTypes {
601    fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {
602        Self(iter.into_iter().collect())
603    }
604}
605
606impl IntoIterator for ResponseTypes {
607    type Item = String;
608    type IntoIter = std::vec::IntoIter<String>;
609    fn into_iter(self) -> Self::IntoIter {
610        self.0.into_iter()
611    }
612}
613
614impl<'a> IntoIterator for &'a ResponseTypes {
615    type Item = &'a String;
616    type IntoIter = std::slice::Iter<'a, String>;
617    fn into_iter(self) -> Self::IntoIter {
618        self.0.iter()
619    }
620}
621
622/// A collection of permissions.
623///
624/// Provides type safety for permission management and prevents confusion
625/// with other string collections.
626///
627/// # Examples
628///
629/// ```rust
630/// use auth_framework::types::Permissions;
631///
632/// let perms = Permissions(vec!["user:read".to_string(), "user:write".to_string()]);
633/// assert!(perms.contains("user:read"));
634/// ```
635#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
636pub struct Permissions(pub Vec<String>);
637
638impl Permissions {
639    /// Create a new Permissions collection
640    pub fn new(permissions: Vec<String>) -> Self {
641        Self(permissions)
642    }
643
644    /// Create an empty Permissions collection
645    pub fn empty() -> Self {
646        Self(Vec::new())
647    }
648
649    /// Get the number of permissions
650    pub fn len(&self) -> usize {
651        self.0.len()
652    }
653
654    /// Check if the collection is empty
655    pub fn is_empty(&self) -> bool {
656        self.0.is_empty()
657    }
658
659    /// Check if a specific permission is present
660    pub fn contains(&self, permission: &str) -> bool {
661        self.0.contains(&permission.to_string())
662    }
663
664    /// Add a permission to the collection
665    pub fn push(&mut self, permission: String) {
666        self.0.push(permission);
667    }
668
669    /// Iterate over the permissions
670    pub fn iter(&self) -> std::slice::Iter<'_, String> {
671        self.0.iter()
672    }
673}
674
675impl Default for Permissions {
676    fn default() -> Self {
677        Self::empty()
678    }
679}
680
681impl From<Vec<String>> for Permissions {
682    fn from(permissions: Vec<String>) -> Self {
683        Self(permissions)
684    }
685}
686
687impl From<Permissions> for Vec<String> {
688    fn from(permissions: Permissions) -> Vec<String> {
689        permissions.0
690    }
691}
692
693impl<S: AsRef<str>> From<&[S]> for Permissions {
694    fn from(slice: &[S]) -> Self {
695        Self(slice.iter().map(|s| s.as_ref().to_owned()).collect())
696    }
697}
698
699impl Deref for Permissions {
700    type Target = Vec<String>;
701    fn deref(&self) -> &Self::Target {
702        &self.0
703    }
704}
705
706impl std::ops::DerefMut for Permissions {
707    fn deref_mut(&mut self) -> &mut Self::Target {
708        &mut self.0
709    }
710}
711
712impl FromIterator<String> for Permissions {
713    fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {
714        Self(iter.into_iter().collect())
715    }
716}
717
718impl IntoIterator for Permissions {
719    type Item = String;
720    type IntoIter = std::vec::IntoIter<String>;
721    fn into_iter(self) -> Self::IntoIter {
722        self.0.into_iter()
723    }
724}
725
726impl<'a> IntoIterator for &'a Permissions {
727    type Item = &'a String;
728    type IntoIter = std::slice::Iter<'a, String>;
729    fn into_iter(self) -> Self::IntoIter {
730        self.0.iter()
731    }
732}
733
734#[cfg(feature = "postgres-storage")]
735impl sqlx::Type<sqlx::Postgres> for Permissions {
736    fn type_info() -> sqlx::postgres::PgTypeInfo {
737        <Vec<String> as sqlx::Type<sqlx::Postgres>>::type_info()
738    }
739    fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {
740        <Vec<String> as sqlx::Type<sqlx::Postgres>>::compatible(ty)
741    }
742}
743
744#[cfg(feature = "postgres-storage")]
745impl<'r> sqlx::Decode<'r, sqlx::Postgres> for Permissions {
746    fn decode(value: sqlx::postgres::PgValueRef<'r>) -> Result<Self, sqlx::error::BoxDynError> {
747        let inner = <Vec<String> as sqlx::Decode<'r, sqlx::Postgres>>::decode(value)?;
748        Ok(Self(inner))
749    }
750}
751
752#[cfg(feature = "postgres-storage")]
753impl<'q> sqlx::Encode<'q, sqlx::Postgres> for Permissions {
754    fn encode_by_ref(
755        &self,
756        buf: &mut sqlx::postgres::PgArgumentBuffer,
757    ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
758        <Vec<String> as sqlx::Encode<'q, sqlx::Postgres>>::encode_by_ref(&self.0, buf)
759    }
760}
761
762/// User attributes as key-value pairs.
763///
764/// Provides type safety for user attribute management and prevents confusion
765/// with other `HashMap` types.
766///
767/// # Examples
768///
769/// ```rust
770/// use auth_framework::types::UserAttributes;
771/// use std::collections::HashMap;
772///
773/// let mut attrs = HashMap::new();
774/// attrs.insert("department".to_string(), "engineering".to_string());
775/// let user_attrs = UserAttributes::new(attrs);
776/// assert_eq!(user_attrs.get("department"), Some(&"engineering".to_string()));
777/// ```
778#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
779pub struct UserAttributes(pub HashMap<String, String>);
780
781impl UserAttributes {
782    /// Creates a new `UserAttributes` from the given map.
783    pub fn new(attributes: HashMap<String, String>) -> Self {
784        Self(attributes)
785    }
786
787    /// Create an empty UserAttributes collection
788    pub fn empty() -> Self {
789        Self(HashMap::new())
790    }
791
792    /// Get the number of attributes
793    pub fn len(&self) -> usize {
794        self.0.len()
795    }
796
797    /// Check if the collection is empty
798    pub fn is_empty(&self) -> bool {
799        self.0.is_empty()
800    }
801
802    /// Get a specific attribute value
803    pub fn get(&self, key: &str) -> Option<&String> {
804        self.0.get(key)
805    }
806
807    /// Set an attribute value
808    pub fn insert(&mut self, key: String, value: String) -> Option<String> {
809        self.0.insert(key, value)
810    }
811
812    /// Remove an attribute
813    pub fn remove(&mut self, key: &str) -> Option<String> {
814        self.0.remove(key)
815    }
816
817    /// Iterate over the attributes
818    pub fn iter(&self) -> std::collections::hash_map::Iter<'_, String, String> {
819        self.0.iter()
820    }
821}
822
823impl Default for UserAttributes {
824    fn default() -> Self {
825        Self::empty()
826    }
827}
828
829impl From<HashMap<String, String>> for UserAttributes {
830    fn from(attributes: HashMap<String, String>) -> Self {
831        Self(attributes)
832    }
833}
834
835impl From<UserAttributes> for HashMap<String, String> {
836    fn from(attributes: UserAttributes) -> HashMap<String, String> {
837        attributes.0
838    }
839}
840
841impl Deref for UserAttributes {
842    type Target = HashMap<String, String>;
843    fn deref(&self) -> &Self::Target {
844        &self.0
845    }
846}
847
848impl std::ops::DerefMut for UserAttributes {
849    fn deref_mut(&mut self) -> &mut Self::Target {
850        &mut self.0
851    }
852}
853
854impl<'a> IntoIterator for &'a UserAttributes {
855    type Item = (&'a String, &'a String);
856    type IntoIter = std::collections::hash_map::Iter<'a, String, String>;
857    fn into_iter(self) -> Self::IntoIter {
858        self.0.iter()
859    }
860}
861
862/// User attributes as key-value pairs (string values).
863///
864/// Provides type safety for user attribute management in contexts where
865/// string values are expected (e.g., UserContext).
866///
867/// # Examples
868///
869/// ```rust
870/// use auth_framework::types::UserAttributesString;
871/// use std::collections::HashMap;
872///
873/// let mut attrs = HashMap::new();
874/// attrs.insert("department".to_string(), "engineering".to_string());
875/// let user_attrs = UserAttributesString(attrs);
876/// ```
877#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
878pub struct UserAttributesString(pub HashMap<String, String>);
879
880impl UserAttributesString {
881    /// Create a new UserAttributesString collection
882    pub fn new(attributes: HashMap<String, String>) -> Self {
883        Self(attributes)
884    }
885
886    /// Create an empty UserAttributesString collection
887    pub fn empty() -> Self {
888        Self(HashMap::new())
889    }
890
891    /// Get the number of attributes
892    pub fn len(&self) -> usize {
893        self.0.len()
894    }
895
896    /// Check if the collection is empty
897    pub fn is_empty(&self) -> bool {
898        self.0.is_empty()
899    }
900
901    /// Get a specific attribute value
902    pub fn get(&self, key: &str) -> Option<&String> {
903        self.0.get(key)
904    }
905
906    /// Set an attribute value
907    pub fn insert(&mut self, key: String, value: String) -> Option<String> {
908        self.0.insert(key, value)
909    }
910
911    /// Remove an attribute
912    pub fn remove(&mut self, key: &str) -> Option<String> {
913        self.0.remove(key)
914    }
915
916    /// Iterate over the attributes
917    pub fn iter(&self) -> std::collections::hash_map::Iter<'_, String, String> {
918        self.0.iter()
919    }
920}
921
922impl Default for UserAttributesString {
923    fn default() -> Self {
924        Self::empty()
925    }
926}
927
928impl From<HashMap<String, String>> for UserAttributesString {
929    fn from(attributes: HashMap<String, String>) -> Self {
930        Self(attributes)
931    }
932}
933
934impl From<UserAttributesString> for HashMap<String, String> {
935    fn from(attributes: UserAttributesString) -> HashMap<String, String> {
936        attributes.0
937    }
938}
939
940impl Deref for UserAttributesString {
941    type Target = HashMap<String, String>;
942    fn deref(&self) -> &Self::Target {
943        &self.0
944    }
945}
946
947impl std::ops::DerefMut for UserAttributesString {
948    fn deref_mut(&mut self) -> &mut Self::Target {
949        &mut self.0
950    }
951}
952
953impl<'a> IntoIterator for &'a UserAttributesString {
954    type Item = (&'a String, &'a String);
955    type IntoIter = std::collections::hash_map::Iter<'a, String, String>;
956    fn into_iter(self) -> Self::IntoIter {
957        self.0.iter()
958    }
959}
960
961/// IP address whitelist for access control.
962///
963/// Provides type safety for IP address management with validation.
964///
965/// # Examples
966///
967/// ```rust
968/// use auth_framework::types::IpList;
969///
970/// let ips = IpList(vec!["192.168.1.1".to_string(), "10.0.0.1".to_string()]);
971/// assert!(ips.contains("192.168.1.1"));
972/// ```
973#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
974pub struct IpList(pub Vec<String>);
975
976impl IpList {
977    /// Create a new IpList
978    pub fn new(ips: Vec<String>) -> Self {
979        Self(ips)
980    }
981
982    /// Create an empty IpList
983    pub fn empty() -> Self {
984        Self(Vec::new())
985    }
986
987    /// Get the number of IP addresses
988    pub fn len(&self) -> usize {
989        self.0.len()
990    }
991
992    /// Check if the list is empty
993    pub fn is_empty(&self) -> bool {
994        self.0.is_empty()
995    }
996
997    /// Check if a specific IP is in the list
998    pub fn contains(&self, ip: &str) -> bool {
999        self.0.contains(&ip.to_string())
1000    }
1001
1002    /// Add an IP to the list
1003    pub fn push(&mut self, ip: String) {
1004        self.0.push(ip);
1005    }
1006
1007    /// Iterate over the IPs
1008    pub fn iter(&self) -> std::slice::Iter<'_, String> {
1009        self.0.iter()
1010    }
1011}
1012
1013impl Default for IpList {
1014    fn default() -> Self {
1015        Self::empty()
1016    }
1017}
1018
1019impl From<Vec<String>> for IpList {
1020    fn from(ips: Vec<String>) -> Self {
1021        Self(ips)
1022    }
1023}
1024
1025impl From<IpList> for Vec<String> {
1026    fn from(ips: IpList) -> Vec<String> {
1027        ips.0
1028    }
1029}
1030
1031impl<S: AsRef<str>> From<&[S]> for IpList {
1032    fn from(slice: &[S]) -> Self {
1033        Self(slice.iter().map(|s| s.as_ref().to_owned()).collect())
1034    }
1035}
1036
1037impl Deref for IpList {
1038    type Target = Vec<String>;
1039    fn deref(&self) -> &Self::Target {
1040        &self.0
1041    }
1042}
1043
1044impl std::ops::DerefMut for IpList {
1045    fn deref_mut(&mut self) -> &mut Self::Target {
1046        &mut self.0
1047    }
1048}
1049
1050impl FromIterator<String> for IpList {
1051    fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {
1052        Self(iter.into_iter().collect())
1053    }
1054}
1055
1056impl IntoIterator for IpList {
1057    type Item = String;
1058    type IntoIter = std::vec::IntoIter<String>;
1059    fn into_iter(self) -> Self::IntoIter {
1060        self.0.into_iter()
1061    }
1062}
1063
1064impl<'a> IntoIterator for &'a IpList {
1065    type Item = &'a String;
1066    type IntoIter = std::slice::Iter<'a, String>;
1067    fn into_iter(self) -> Self::IntoIter {
1068        self.0.iter()
1069    }
1070}
1071
1072/// Custom parameters to include in OAuth authorization requests.
1073///
1074/// Wraps a `HashMap<String, String>` for type safety. Commonly used with
1075/// [`OAuthProviderConfig`](crate::providers::OAuthProviderConfig) to pass
1076/// provider-specific query parameters.
1077///
1078/// # Examples
1079///
1080/// ```rust
1081/// use auth_framework::types::AdditionalParams;
1082///
1083/// let mut params = AdditionalParams::new();
1084/// params.insert("prompt", "consent");
1085/// params.insert("access_type", "offline");
1086/// assert_eq!(params.len(), 2);
1087/// ```
1088#[derive(Debug, Clone, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
1089pub struct AdditionalParams(pub HashMap<String, String>);
1090
1091impl AdditionalParams {
1092    /// Creates an empty parameter set.
1093    pub fn new() -> Self {
1094        Self(HashMap::new())
1095    }
1096
1097    /// Inserts a key-value pair, overwriting any previous value for `key`.
1098    pub fn insert(&mut self, key: impl Into<String>, value: impl Into<String>) {
1099        self.0.insert(key.into(), value.into());
1100    }
1101}
1102
1103impl Deref for AdditionalParams {
1104    type Target = HashMap<String, String>;
1105    fn deref(&self) -> &Self::Target {
1106        &self.0
1107    }
1108}
1109
1110impl std::ops::DerefMut for AdditionalParams {
1111    fn deref_mut(&mut self) -> &mut Self::Target {
1112        &mut self.0
1113    }
1114}
1115
1116impl<'a> IntoIterator for &'a AdditionalParams {
1117    type Item = (&'a String, &'a String);
1118    type IntoIter = std::collections::hash_map::Iter<'a, String, String>;
1119    fn into_iter(self) -> Self::IntoIter {
1120        self.0.iter()
1121    }
1122}
1123
1124impl From<HashMap<String, String>> for AdditionalParams {
1125    fn from(map: HashMap<String, String>) -> Self {
1126        Self(map)
1127    }
1128}
1129
1130impl From<AdditionalParams> for HashMap<String, String> {
1131    fn from(params: AdditionalParams) -> HashMap<String, String> {
1132        params.0
1133    }
1134}