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
//! Profile management for rcman
//!
//! This module provides profile support for settings and sub-settings,
//! allowing multiple named configurations that can be switched at runtime.
//!
//! # Overview
//!
//! Profiles allow users to maintain multiple configurations (e.g., "work", "personal", "testing")
//! and switch between them dynamically. Profiles can be scoped to:
//!
//!
//! # When to Use Profiles
//!
//! Profiles add complexity to the storage structure and API interaction. They should be chosen deliberately.
//!
//! ## ✅ Good Use Cases
//!
//! - **Multi-tenant Applications**: Where different users/tenants need completely isolated configurations.
//! - **Environment Switching**: Dev/Staging/Prod environments that need to swap entirely different sets of remotes or settings.
//! - **Workspace Management**: Applications that support distinct workspaces (like VS Code profiles).
//!
//! ## ❌ Avoid If
//!
//! - **Simple Presets**: If you just want to save a few combinations of settings, use a "presets" list in your main settings instead.
//! - **Single User Apps**: If the app is for a single user, profiles often add confusion.
//! - **Small Configs**: If your total config is < 10 items, profiling is likely over-engineering.
//!
//! # Performance & Complexity Impact
//!
//! Enabling profiles changes the on-disk structure:
//!
//! - **Standard:** `config_dir/remotes.json` (simple, fast)
//! - **Profiled:** `config_dir/remotes/profiles/{profile_name}/...` + `.profiles.json` manifest
//!
//! This introduces:
//! - **Initialization Cost:** Migration logic must run on startup to move flat files into the default profile.
//! - **I/O Overhead:** Switching profiles invalidates in-memory caches and requires re-reading from disk.
//! - **API Complexity:** You must manage profile lifecycle (create/switch/delete).
//!
//! # Implementation Details
//!
//! Profile management leverages a `.profiles.{ext}` manifest file stored at the target directory root.
//! This manifest acts as the source of truth for tracking the `active` profile name and the list
//! of all existing profiles. When a profile is created or switched, operations are dynamically routed
//! to the nested `profiles/{profile_name}/` directory.
//!
//! To prevent blocking operations in highly concurrent environments (like web servers routing requests
//! by tenant profile), the `ProfileManager` caches the manifest in an `RwLock` and eagerly clones it
//! out of the lock before executing blocking disk I/O. Legacy data is transparently migrated into
//! the `.profiles` folder schema by `ProfileMigrator` seamlessly during boot.
//!
//! # Example
//!
//! ```rust,ignore
//! use rcman::{SettingsManager, SubSettingsConfig};
//!
//! // Enable profiles for remotes sub-settings
//! let manager = SettingsManager::builder("my-app", "1.0.0")
//! .with_sub_settings(SubSettingsConfig::new("remotes").with_profiles())
//! .build()?;
//!
//! // Manage profiles
//! let remotes = manager.sub_settings("remotes")?;
//! remotes.profiles()?.create("work")?;
//! remotes.profiles()?.switch("work")?;
//!
//! // CRUD now operates on "work" profile
//! remotes.set("company-drive", &json!({...}))?;
//! ```
pub use ;
pub use ;
/// Default profile name used when migrating or initializing
pub const DEFAULT_PROFILE: &str = "default";
/// Directory name containing profile subdirectories
pub const PROFILES_DIR: &str = "profiles";
/// Validate a profile name
///
/// Valid names can contain spaces and most printable characters.
/// Names cannot be empty, start with a dot, or contain path separators.
///
/// # Errors
///
/// Returns an error if the name is invalid.