offset_string/
conversions.rs
1use crate::OffsetString;
6use anyhow::{format_err, Error};
7use char_collection::{CharCollection, MultiCharRange};
8use char_set::CharSet;
9use unic_char_range::{chars, CharRange};
10
11impl TryFrom<String> for OffsetString {
12 type Error = anyhow::Error;
13
14 fn try_from(source: String) -> Result<OffsetString, Error> {
15 OffsetString::new(source)
16 }
17}
18
19impl TryFrom<&str> for OffsetString {
20 type Error = anyhow::Error;
21
22 fn try_from(source: &str) -> Result<OffsetString, Error> {
23 OffsetString::new(source)
24 }
25}
26
27impl From<OffsetString> for String {
28 fn from(value: OffsetString) -> String {
29 value.0
30 }
31}
32
33impl From<CharCollection> for OffsetString {
34 fn from(value: CharCollection) -> OffsetString {
35 OffsetString::from(&value)
36 }
37}
38
39impl From<&CharCollection> for OffsetString {
40 fn from(value: &CharCollection) -> OffsetString {
41 let mut prev_high: u32 = 0;
42 let mut segments: Vec<String> = Vec::with_capacity(value.range_count());
43 for range in value.iter_ranges() {
44 let relative_low = range.low as u32 - prev_high;
45 let range_size = range.len();
46 let segment = if range_size == 1 {
47 relative_low.to_string()
48 } else {
49 format!("{}+{}", relative_low, range_size - 1)
50 };
51 segments.push(segment);
52 prev_high = range.high as u32;
53 }
54 OffsetString(segments.join(","))
55 }
56}
57
58impl TryFrom<OffsetString> for CharCollection {
59 type Error = anyhow::Error;
60
61 fn try_from(value: OffsetString) -> Result<Self, Self::Error> {
62 CharCollection::try_from(&value)
63 }
64}
65
66impl TryFrom<&OffsetString> for CharCollection {
67 type Error = anyhow::Error;
68
69 fn try_from(value: &OffsetString) -> Result<Self, Self::Error> {
70 let ranges: Result<Vec<CharRange>, Error> = value
71 .iter_ranges()
72 .map(|range| {
73 let low: u32 = *range.start();
74 let high: u32 = *range.end();
75 let low_char =
76 std::char::from_u32(low).ok_or_else(|| format_err!("Bad char: {}", low))?;
77 let high_char =
78 std::char::from_u32(high).ok_or_else(|| format_err!("Bad char: {}", high))?;
79 Ok(chars!(low_char..=high_char))
80 })
81 .collect();
82 return CharCollection::from_sorted_ranges(ranges?);
83 }
84}
85
86impl From<CharSet> for OffsetString {
87 fn from(value: CharSet) -> OffsetString {
88 OffsetString::from(&value)
89 }
90}
91
92impl From<&CharSet> for OffsetString {
93 fn from(char_set: &CharSet) -> OffsetString {
94 let collection: CharCollection = char_set.into();
95 collection.into()
96 }
97}
98
99impl TryFrom<OffsetString> for CharSet {
100 type Error = anyhow::Error;
101
102 fn try_from(value: OffsetString) -> Result<Self, Self::Error> {
103 CharSet::try_from(&value)
104 }
105}
106
107impl TryFrom<&OffsetString> for CharSet {
108 type Error = anyhow::Error;
109
110 fn try_from(value: &OffsetString) -> Result<Self, Self::Error> {
111 Ok(CharSet::new(value.iter().collect()))
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118 use char_collection::char_collect;
119
120 #[test]
121 fn test_char_collection_to_offset_string() -> Result<(), Error> {
122 let collection = char_collect!(0..=4, 9..=9, 20..=28);
123 let offset_string: OffsetString = collection.into();
124 assert_eq!(offset_string, OffsetString::new("0+4,5,11+8")?);
125
126 let collection = char_collect!(3..=4, 9..=9, 20..=28);
127 let offset_string: OffsetString = collection.into();
128 assert_eq!(offset_string, OffsetString("3+1,5,11+8".to_string()));
129
130 Ok(())
131 }
132
133 #[test]
134 fn test_char_collection_from_offset_string() -> Result<(), Error> {
135 assert_eq!(
136 char_collect!(0..=4, 9..=9, 20..=28),
137 CharCollection::try_from(OffsetString::new("0+4,5,11+8")?)?
138 );
139
140 assert_eq!(
141 char_collect!(3..=4, 9..=9, 20..=28),
142 CharCollection::try_from(OffsetString::new("3+1,5,11+8")?)?
143 );
144
145 Ok(())
146 }
147}