1use crate::dataset::DataSet;
6use crate::value::Value;
7use dicom_toolkit_dict::{Tag, Vr};
8use std::fmt;
9
10#[derive(Debug, Clone, PartialEq)]
12pub struct Element {
13 pub tag: Tag,
14 pub vr: Vr,
15 pub value: Value,
16}
17
18impl Element {
19 pub fn new(tag: Tag, vr: Vr, value: Value) -> Self {
22 Self { tag, vr, value }
23 }
24
25 pub fn string(tag: Tag, vr: Vr, s: &str) -> Self {
27 Self::new(tag, vr, Value::Strings(vec![s.to_string()]))
28 }
29
30 pub fn strings(tag: Tag, vr: Vr, values: &[&str]) -> Self {
32 Self::new(
33 tag,
34 vr,
35 Value::Strings(values.iter().map(|s| s.to_string()).collect()),
36 )
37 }
38
39 pub fn u16(tag: Tag, value: u16) -> Self {
40 Self::new(tag, Vr::US, Value::U16(vec![value]))
41 }
42
43 pub fn u32(tag: Tag, value: u32) -> Self {
44 Self::new(tag, Vr::UL, Value::U32(vec![value]))
45 }
46
47 pub fn i32(tag: Tag, value: i32) -> Self {
48 Self::new(tag, Vr::SL, Value::I32(vec![value]))
49 }
50
51 pub fn f64(tag: Tag, value: f64) -> Self {
52 Self::new(tag, Vr::FD, Value::F64(vec![value]))
53 }
54
55 pub fn bytes(tag: Tag, vr: Vr, data: Vec<u8>) -> Self {
56 Self::new(tag, vr, Value::U8(data))
57 }
58
59 pub fn sequence(tag: Tag, items: Vec<DataSet>) -> Self {
60 Self::new(tag, Vr::SQ, Value::Sequence(items))
61 }
62
63 pub fn uid(tag: Tag, uid: &str) -> Self {
64 Self::new(tag, Vr::UI, Value::Uid(uid.to_string()))
65 }
66
67 pub fn is_empty(&self) -> bool {
70 self.value.is_empty()
71 }
72
73 pub fn string_value(&self) -> Option<&str> {
74 self.value.as_string()
75 }
76
77 pub fn strings_value(&self) -> Option<&[String]> {
78 self.value.as_strings()
79 }
80
81 pub fn u16_value(&self) -> Option<u16> {
82 self.value.as_u16()
83 }
84
85 pub fn u32_value(&self) -> Option<u32> {
86 self.value.as_u32()
87 }
88
89 pub fn i32_value(&self) -> Option<i32> {
90 self.value.as_i32()
91 }
92
93 pub fn f64_value(&self) -> Option<f64> {
94 self.value.as_f64()
95 }
96
97 pub fn bytes_value(&self) -> Option<&[u8]> {
98 self.value.as_bytes()
99 }
100
101 pub fn items(&self) -> Option<&[DataSet]> {
102 match &self.value {
103 Value::Sequence(items) => Some(items.as_slice()),
104 _ => None,
105 }
106 }
107}
108
109impl fmt::Display for Element {
110 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 let tag_str = format!("({:04X},{:04X})", self.tag.group, self.tag.element);
113 let vr_str = self.vr.code();
114 let display_val = self.value.to_display_string();
115 let length = self.value.encoded_len();
116 let mult = self.value.multiplicity();
117
118 let value_part = if self.vr.is_string()
120 || matches!(self.vr, Vr::UI | Vr::PN | Vr::DA | Vr::TM | Vr::DT | Vr::AT)
121 {
122 if display_val.is_empty() {
123 "(no value available)".to_string()
124 } else {
125 format!("[{}]", display_val)
126 }
127 } else {
128 display_val
129 };
130
131 write!(
132 f,
133 "{} {} {} # {}, {}",
134 tag_str, vr_str, value_part, length, mult
135 )
136 }
137}
138
139#[cfg(test)]
142mod tests {
143 use super::*;
144 use dicom_toolkit_dict::tags;
145
146 #[test]
147 fn element_string_roundtrip() {
148 let e = Element::string(tags::PATIENT_NAME, Vr::PN, "Smith^John");
149 assert_eq!(e.string_value(), Some("Smith^John"));
150 assert!(!e.is_empty());
151 }
152
153 #[test]
154 fn element_strings_roundtrip() {
155 let e = Element::strings(tags::IMAGE_TYPE, Vr::CS, &["ORIGINAL", "PRIMARY"]);
156 let s = e.strings_value().unwrap();
157 assert_eq!(s, &["ORIGINAL", "PRIMARY"]);
158 assert_eq!(e.value.multiplicity(), 2);
159 }
160
161 #[test]
162 fn element_u16_roundtrip() {
163 let e = Element::u16(tags::ROWS, 512);
164 assert_eq!(e.u16_value(), Some(512));
165 assert_eq!(e.vr, Vr::US);
166 }
167
168 #[test]
169 fn element_u32_roundtrip() {
170 let e = Element::u32(tags::STUDY_INSTANCE_UID, 999);
171 assert_eq!(e.u32_value(), Some(999));
173 assert_eq!(e.vr, Vr::UL);
174 }
175
176 #[test]
177 fn element_i32_roundtrip() {
178 let tag = Tag::new(0x0020, 0x0013);
179 let e = Element::i32(tag, -42);
180 assert_eq!(e.i32_value(), Some(-42));
181 assert_eq!(e.vr, Vr::SL);
182 }
183
184 #[test]
185 fn element_f64_roundtrip() {
186 let tag = Tag::new(0x0018, 0x0050);
187 let e = Element::f64(tag, 2.78);
188 assert!((e.f64_value().unwrap() - 2.78).abs() < 1e-9);
189 assert_eq!(e.vr, Vr::FD);
190 }
191
192 #[test]
193 fn element_bytes_roundtrip() {
194 let tag = Tag::new(0x0042, 0x0011);
195 let data = vec![0xDE, 0xAD, 0xBE, 0xEF];
196 let e = Element::bytes(tag, Vr::OB, data.clone());
197 assert_eq!(e.bytes_value(), Some(data.as_slice()));
198 }
199
200 #[test]
201 fn element_uid_roundtrip() {
202 let e = Element::uid(tags::SOP_CLASS_UID, "1.2.840.10008.1.1");
203 assert_eq!(e.string_value(), Some("1.2.840.10008.1.1"));
204 assert_eq!(e.vr, Vr::UI);
205 }
206
207 #[test]
208 fn element_sequence_roundtrip() {
209 let item = DataSet::new();
210 let e = Element::sequence(Tag::new(0x0008, 0x1115), vec![item]);
211 assert_eq!(e.items().unwrap().len(), 1);
212 assert_eq!(e.vr, Vr::SQ);
213 }
214
215 #[test]
216 fn element_display_string() {
217 let e = Element::string(tags::PATIENT_NAME, Vr::PN, "Smith^John");
218 let s = e.to_string();
219 assert!(s.contains("(0010,0010)"), "tag not in display: {}", s);
220 assert!(s.contains("PN"), "VR not in display: {}", s);
221 assert!(s.contains("[Smith^John]"), "value not in display: {}", s);
222 assert!(s.contains("# "), "length marker missing: {}", s);
224 assert!(s.contains(", 1"), "multiplicity not in display: {}", s);
225 }
226
227 #[test]
228 fn element_display_u16() {
229 let e = Element::u16(tags::ROWS, 512);
230 let s = e.to_string();
231 assert!(s.contains("(0028,0010)"), "tag not in display: {}", s);
232 assert!(s.contains("US"), "VR not in display: {}", s);
233 assert!(s.contains("512"), "value not in display: {}", s);
234 }
235
236 #[test]
237 fn element_is_empty() {
238 let e = Element::new(tags::PATIENT_NAME, Vr::PN, Value::Empty);
239 assert!(e.is_empty());
240 }
241}