pub const NAMEDATALEN: usize = 64;
pub fn clip(name: &str, len: usize) -> &str {
let mut end = len.min(name.len());
while !name.is_char_boundary(end) {
end -= 1;
}
&name[..end]
}
pub fn make_object_name(name1: &str, name2: Option<&str>, label: Option<&str>) -> String {
let mut overhead = 0;
let mut name1_len = name1.len();
let mut name2_len = 0;
if let Some(name2) = name2 {
name2_len = name2.len();
overhead += 1;
}
if let Some(label) = label {
overhead += label.len() + 1;
}
let available = (NAMEDATALEN - 1).saturating_sub(overhead);
while name1_len + name2_len > available {
if name1_len > name2_len {
name1_len -= 1;
} else {
name2_len -= 1;
}
}
let mut name = clip(name1, name1_len).to_string();
if let Some(name2) = name2 {
name.push('_');
name.push_str(clip(name2, name2_len));
}
if let Some(label) = label {
name.push('_');
name.push_str(label);
}
name
}
pub fn name_addition<'a>(names: impl IntoIterator<Item = &'a str>) -> String {
let mut addition = String::new();
for name in names {
if !addition.is_empty() {
addition.push('_');
}
addition.push_str(clip(name, NAMEDATALEN - 1));
if addition.len() >= NAMEDATALEN {
break;
}
}
addition
}
pub fn index_column_names<'a>(names: impl IntoIterator<Item = &'a str>) -> Vec<String> {
let mut result: Vec<String> = Vec::new();
for original in names {
let mut name = original.to_string();
let mut suffix = 1;
while result.contains(&name) {
let digits = suffix.to_string();
name = format!("{}{digits}", clip(original, NAMEDATALEN - 1 - digits.len()));
suffix += 1;
}
result.push(name);
}
result
}