1use std::fmt;
2use std::str::FromStr;
3
4use anyhow::{anyhow, bail};
5use clap::ValueEnum;
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ValueEnum)]
9#[serde(rename_all = "snake_case")]
10#[value(rename_all = "snake_case")]
11pub enum MemoryMode {
12 #[default]
13 Global,
14 Workspace,
15 Session,
16}
17
18impl MemoryMode {
19 pub fn as_str(self) -> &'static str {
20 match self {
21 Self::Global => "global",
22 Self::Workspace => "workspace",
23 Self::Session => "session",
24 }
25 }
26}
27
28impl fmt::Display for MemoryMode {
29 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
30 formatter.write_str(self.as_str())
31 }
32}
33
34impl FromStr for MemoryMode {
35 type Err = anyhow::Error;
36
37 fn from_str(value: &str) -> Result<Self, Self::Err> {
38 match value.trim().to_ascii_lowercase().as_str() {
39 "global" => Ok(Self::Global),
40 "workspace" => Ok(Self::Workspace),
41 "session" => Ok(Self::Session),
42 other => bail!("unsupported memory mode: {other}"),
43 }
44 }
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ValueEnum)]
48#[serde(rename_all = "snake_case")]
49#[value(rename_all = "snake_case")]
50pub enum ExpirationCondition {
51 Time,
52 Usage,
53 FileExist,
54 FilePristine,
55 Period,
56}
57
58impl ExpirationCondition {
59 pub fn as_str(self) -> &'static str {
60 match self {
61 Self::Time => "time",
62 Self::Usage => "usage",
63 Self::FileExist => "file_exist",
64 Self::FilePristine => "file_pristine",
65 Self::Period => "period",
66 }
67 }
68}
69
70impl fmt::Display for ExpirationCondition {
71 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
72 formatter.write_str(self.as_str())
73 }
74}
75
76impl FromStr for ExpirationCondition {
77 type Err = anyhow::Error;
78
79 fn from_str(value: &str) -> Result<Self, Self::Err> {
80 match value.trim().to_ascii_lowercase().as_str() {
81 "time" => Ok(Self::Time),
82 "usage" => Ok(Self::Usage),
83 "file_exist" | "file-exist" => Ok(Self::FileExist),
84 "file_pristine" | "file-pristine" => Ok(Self::FilePristine),
85 "period" => Ok(Self::Period),
86 other => Err(anyhow!("unsupported expiration condition: {other}")),
87 }
88 }
89}
90
91pub fn normalize_tags(tags: &[String]) -> Vec<String> {
92 let mut normalized = Vec::new();
93
94 for tag in tags {
95 let tag = tag.trim().to_ascii_lowercase();
96 if tag.is_empty() || normalized.contains(&tag) {
97 continue;
98 }
99 normalized.push(tag);
100 }
101
102 normalized
103}