1use one_or_many::OneOrMany;
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
8#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
9#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
10pub enum MetadataConflictResolution {
11 #[default]
12 Overwrite,
13 Skip,
14}
15
16#[cfg(all(test, feature = "serde"))]
17mod metadata_conflict_resolution {
18 use rstest::rstest;
19
20 use super::*;
21
22 #[test]
23 fn test_default() {
24 assert_eq!(
25 MetadataConflictResolution::default(),
26 MetadataConflictResolution::Overwrite
27 );
28 }
29
30 #[rstest]
31 #[case::lower(MetadataConflictResolution::Overwrite, "overwrite")]
32 #[case::lower(MetadataConflictResolution::Skip, "skip")]
33 fn test_deserialize<D, 'de>(#[case] expected: MetadataConflictResolution, #[case] input: D)
34 where
35 D: serde::de::IntoDeserializer<'de>,
36 {
37 let actual: MetadataConflictResolution =
38 MetadataConflictResolution::deserialize(input.into_deserializer()).unwrap();
39 assert_eq!(actual, expected);
40 }
41}
42
43#[inline]
54#[must_use]
55pub fn split_artist_name(
56 artist: &str,
57 artist_name_separator: &OneOrMany<String>,
58 exceptions: &OneOrMany<String>,
59) -> OneOrMany<String> {
60 let mut artists = OneOrMany::None;
61
62 let mut left = 0;
64 let mut right = 0;
65 while right < artist.len() {
66 let rest_right = &artist[right..];
67 if let Some(sep) = artist_name_separator
69 .iter()
70 .find(|sep| rest_right.starts_with(*sep))
71 {
72 let rest_left = &artist[left..];
73 if let Some(exception) = exceptions
75 .iter()
76 .find(|exception| rest_left.starts_with(*exception))
77 {
78 let exception_len = exception.len();
79 let after_exception = &artist[left + exception_len..];
81 if after_exception.is_empty() {
83 break;
84 }
85 if let Some(sep) = artist_name_separator
86 .iter()
87 .find(|sep| after_exception.starts_with(*sep))
88 {
89 let new = artist[left..left + exception_len].trim().replace('\0', "");
91 if !new.is_empty() {
92 artists.push(new);
93 }
94 left += exception_len + sep.len();
95 right = left;
96 continue;
97 }
98 }
99 let new = artist[left..right].trim().replace('\0', "");
101 if !new.is_empty() {
102 artists.push(new);
103 }
104 right += sep.len();
105 left = right;
106 } else {
107 right += 1;
109 while !artist.is_char_boundary(right) && right < artist.len() {
111 right += 1;
112 }
113 }
114 }
115
116 if left < artist.len() {
118 let new = artist[left..].trim().replace('\0', "");
119 if !new.is_empty() {
120 artists.push(new);
121 }
122 }
123 artists
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129 use rstest::rstest;
130
131 #[rstest]
132 #[case::no_separation("Foo & Bar", &[], &[], vec!["Foo & Bar"])]
133 #[case::redundant_separation("Foo & Bar", &["&", " ", " &", " & "], &[], vec!["Foo", "Bar"])]
134 #[case::separation_no_exclusions("Foo & BarBaz", &["&", ";"], &[], vec!["Foo","BarBaz"])]
135 #[case::separation_no_exclusions("Foo & Bar; Baz", &["&", ";"], &[], vec!["Foo", "Bar", "Baz"])]
136 #[case::separation_excluded("Foo & Bar", &["&", ";"], &["Foo & Bar"], vec!["Foo & Bar"])]
137 #[case::separation_excluded("Foo & BarBaz", &["&", ";"], &["Foo & Bar"], vec!["Foo","BarBaz"])]
138 #[case::separation_excluded("Foo & Bar; Baz", &["&", ";"], &["Foo & Bar"], vec!["Foo & Bar", "Baz"])]
139 #[case::separation_excluded("Foo & BarBaz; Zing", &["&", ";"], &["Foo & Bar"], vec!["Foo","BarBaz", "Zing"])]
140 #[case::separation_excluded("Zing; Foo & BarBaz", &["&", ";"], &["Foo & Bar"], vec!["Zing","Foo","BarBaz"])]
141 #[case::separation_excluded("Foo & Bar; Baz; Zing", &["&", ";"], &["Foo & Bar"], vec!["Foo & Bar", "Baz", "Zing"])]
142 fn test_split_artist_name(
143 #[case] artist: &str,
144 #[case] separators: &[&str],
145 #[case] exceptions: &[&str],
146 #[case] expected: Vec<&str>,
147 ) {
148 let separators = separators.iter().map(|s| s.to_string()).collect();
149 let exceptions = exceptions.iter().map(|s| s.to_string()).collect();
150 let expected = expected
151 .into_iter()
152 .map(|s| s.to_string())
153 .collect::<OneOrMany<String>>();
154 let artists = split_artist_name(artist, &OneOrMany::Many(separators), &exceptions);
155 assert_eq!(artists, expected);
156 }
157}