rskit_cli/prompt/
choice.rs1use std::fmt;
4
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
12pub struct ChoiceId(String);
13
14impl ChoiceId {
15 #[must_use]
17 pub fn new(id: impl Into<String>) -> Self {
18 Self(id.into())
19 }
20
21 #[must_use]
23 pub fn as_str(&self) -> &str {
24 &self.0
25 }
26
27 #[must_use]
29 pub fn into_string(self) -> String {
30 self.0
31 }
32}
33
34impl From<&str> for ChoiceId {
35 fn from(value: &str) -> Self {
36 Self(value.to_string())
37 }
38}
39
40impl From<String> for ChoiceId {
41 fn from(value: String) -> Self {
42 Self(value)
43 }
44}
45
46impl fmt::Display for ChoiceId {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 f.write_str(&self.0)
49 }
50}
51
52#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
55pub struct Choice {
56 id: ChoiceId,
57 label: String,
58 annotation: Option<String>,
59 recommended: bool,
60}
61
62impl Choice {
63 #[must_use]
65 pub fn new(id: impl Into<ChoiceId>, label: impl Into<String>) -> Self {
66 Self {
67 id: id.into(),
68 label: label.into(),
69 annotation: None,
70 recommended: false,
71 }
72 }
73
74 #[must_use]
76 pub fn with_annotation(mut self, annotation: impl Into<String>) -> Self {
77 self.annotation = Some(annotation.into());
78 self
79 }
80
81 #[must_use]
87 pub const fn recommended(mut self) -> Self {
88 self.recommended = true;
89 self
90 }
91
92 #[must_use]
94 pub const fn id(&self) -> &ChoiceId {
95 &self.id
96 }
97
98 #[must_use]
100 pub fn label(&self) -> &str {
101 &self.label
102 }
103
104 #[must_use]
106 pub fn annotation(&self) -> Option<&str> {
107 self.annotation.as_deref()
108 }
109
110 #[must_use]
112 pub const fn is_recommended(&self) -> bool {
113 self.recommended
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::{Choice, ChoiceId};
120
121 #[test]
122 fn choice_id_borrows_and_consumes_its_string() {
123 let id = ChoiceId::new("rust");
124 assert_eq!(id.as_str(), "rust");
125 assert_eq!(id.into_string(), "rust");
126 }
127
128 #[test]
129 fn choice_id_converts_from_owned_and_borrowed_strings() {
130 assert_eq!(ChoiceId::from("go").as_str(), "go");
131 assert_eq!(ChoiceId::from("node".to_string()).as_str(), "node");
132 }
133
134 #[test]
135 fn choice_id_displays_its_inner_value() {
136 assert_eq!(ChoiceId::new("rust").to_string(), "rust");
137 }
138
139 #[test]
140 fn choice_accessors_expose_metadata() {
141 let choice = Choice::new("rust", "Rust")
142 .with_annotation("detected in dev-deps")
143 .recommended();
144 assert_eq!(choice.id(), &ChoiceId::new("rust"));
145 assert_eq!(choice.label(), "Rust");
146 assert_eq!(choice.annotation(), Some("detected in dev-deps"));
147 assert!(choice.is_recommended());
148
149 let plain = Choice::new("go", "Go");
150 assert_eq!(plain.annotation(), None);
151 assert!(!plain.is_recommended());
152 }
153}