1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//! # profile_kit
//!
//! A flexible, lightweight Rust library for managing user profiles โ framework-agnostic, developer-friendly, and production-ready.
//!
//! ---
//!
//! ## โจ Features
//!
//! - ๐ Pluggable profile storage via trait abstraction
//! - โ๏ธ Designed for composability in any Rust project
//! - ๐ Supports user preferences (language, currency, newsletter opt-in)
//! - ๐งช Easy to test with in-memory implementation
//! - ๐ฆ Lightweight dependencies, ready for web or backend apps
//!
//! ---
//!
//! ## ๐ Quick Start
//!
//! ```rust
//! use serde_json::{json, Value};
//! use uuid::Uuid;
//! use profile_kit::model::{UserAttributes, UserPreferences, UserProfile};
//!
//! let mut prefs = UserPreferences::new();
//! prefs.set_newsletter_opt_in(true);
//! prefs.set_extra("theme".to_string(), json!("dark"));
//! prefs.set_extra("custom_field".to_string(), json!({"key": "value"}));
//!
//! let mut attrs = UserAttributes::new();
//! attrs.set_first_name("John".to_string());
//! attrs.set_last_name("Doe".to_string());
//! attrs.set_extra("theme", Value::String("dark".into()));
//! attrs.set_extra("roles", json!(vec!["admin", "editor"]));
//!
//! let id = Uuid::now_v7().simple();
//! let email = "".to_string();
//! let mut profile = UserProfile::new(id.to_string(), email);
//! profile.set_email("john.doe@example.com".to_string());
//! profile.set_attributes(Some(attrs));
//! profile.set_preferences(Some(prefs));
//!
//! let serialized = serde_json::to_string_pretty(&profile).expect("REASON");
//! println!("Serialized profile: {}", serialized);
//!
//! let deserialized: UserProfile = serde_json::from_str(&serialized).expect("REASON");
//! println!("Deserialized profile: {:?}", deserialized);
//!
//! println!("roles : {:?}", deserialized.get_attributes().expect("REASON").get_extra("roles"));
//! println!("first_name : {:?}", deserialized.get_attributes().expect("REASON").get_first_name());
//! ```
//!
//! ---
//!
//! ## ๐ง Trait-based Storage Example
//!
//! ```rust
//! use std::collections::HashMap;
//! use std::sync::{Arc, RwLock};
//! use profile_kit::error::ProfileKitError;
//! use profile_kit::model::UserProfile;
//! use profile_kit::repository::UserProfileRepository;
//!
//! pub struct InMemoryUserProfileRepository {
//! storage: Arc<RwLock<HashMap<String, UserProfile>>>,
//! }
//!
//! impl InMemoryUserProfileRepository {
//! pub fn new() -> Self {
//! InMemoryUserProfileRepository {
//! storage: Arc::new(RwLock::new(HashMap::new())),
//! }
//! }
//! }
//!
//! impl UserProfileRepository for InMemoryUserProfileRepository {
//! fn get_by_id(&self, id: String) -> Result<Option<UserProfile>, ProfileKitError> {
//! let storage = self.storage.read().map_err(|_| ProfileKitError::StorageError)?;
//! Ok(storage.get(&id).cloned())
//! }
//!
//! fn create(&self, profile: UserProfile) -> Result<(), ProfileKitError> {
//! let mut storage = self.storage.write().map_err(|_| ProfileKitError::StorageError)?;
//! if storage.contains_key(&profile.id) {
//! return Err(ProfileKitError::AlreadyExists);
//! }
//! storage.insert(profile.id.clone(), profile);
//! Ok(())
//! }
//!
//! fn update(&self, profile: UserProfile) -> Result<(), ProfileKitError> {
//! let mut storage = self.storage.write().map_err(|_| ProfileKitError::StorageError)?;
//! if !storage.contains_key(&profile.id) {
//! return Err(ProfileKitError::NotFound);
//! }
//! storage.insert(profile.id.clone(), profile);
//! Ok(())
//! }
//!
//! fn delete(&self, id: String) -> Result<(), ProfileKitError> {
//! let mut storage = self.storage.write().map_err(|_| ProfileKitError::StorageError)?;
//! if storage.remove(&id).is_none() {
//! return Err(ProfileKitError::NotFound);
//! }
//! Ok(())
//! }
//! }
//!
//! use uuid::Uuid;
//! use profile_kit::model;
//!
//! let repo = InMemoryUserProfileRepository::new();
//! let id= Uuid::now_v7().simple();
//! let mut user = UserProfile::new(id.to_string(), "test@example.com".into());
//! user.set_email("john.doe@example.com".to_string());
//!
//! repo.create(user).expect("Failed to create user");
//!
//! println!("id {:?}", id.to_string());
//! println!("id {:?}", repo.get_by_id(id.to_string()));
//! ```
//!
//! ---
//!
//! ## ๐ License
//!
//! This project is licensed under the Apache-2.0 license. [LICENSE](http://www.apache.org/licenses/LICENSE-2.0.txt)
//!
//! ---
//!
//! ## ๐ง Author
//! Jerry Maheswara <jerrymaheswara@gmail.com>
//!
//! ---
//!
//! ## โค๏ธ Built with Love in Rust
//!
//! This project is built with โค๏ธ using **Rust** โ a systems programming language that is safe, fast, and concurrent. Rust is the perfect choice for building reliable and efficient applications.
//!
//! ---
//!
//! ## ๐ Contributing
//!
//! Pull requests, issues, and feedback are welcome!
//! If you find this crate useful, give it a โญ and share it with others in the Rust community.
//!
//! ---
/// Data models representing user profile entities, such as
/// `UserProfile`, `UserAttributes`, and `UserPreferences`.
///
/// This module defines the core domain structures used throughout
/// the application or service layer.
/// Errors that may occur during user profile operations.
///
/// Includes structured error types like `ProfileKitError`
/// which are used across domain and infrastructure boundaries.
/// Repository abstractions for user profile storage and access.
///
/// Defines the `UserProfileRepository` trait, which should be implemented
/// by storage backends such as databases, remote APIs, or mocks.