use backtrace::Backtrace;
use indexmap::IndexMap;
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::cmp::Eq;
use std::collections::HashSet;
use std::fmt::Debug;
use std::hash::{BuildHasher, Hash, Hasher};
pub trait Fillable {}
fn not_same_data<T, R>(dest: &T, src: &R)
where
T: Debug,
R: Debug,
{
warn!(
"Warning: Data not added, but the data is not the same.\n\
Don't know which value to keep. Default to keep. \n\
So we keep the first value.\n\
For more info: {}\n\
--------------------------------\n\
\tNot the same: \n{:#?}\n!=\n{:#?}\n\
--------------------------------",
super::git_issue::link_to_issue_nr(44),
dest,
src
);
print_backtrace("Not the same");
}
fn not_same_id<T, R>(dest: &T, src: &R)
where
T: Debug,
R: Debug,
{
warn!(
"Warning: These items do not have the same identifiers.\n\
But we are trying to merge them in a list. This might result in corrupted data.\n\
This is probably because of a programming error. Stopped merger of data.\n\
--------------------------------\n\
\tDifferent identifiers: \n{:#?}\n!=\n{:#?}\n\
--------------------------------",
dest, src
);
print_backtrace("Different identifiers");
}
fn print_backtrace(name: &str) {
let bt = Backtrace::new();
let frames = bt.frames();
let mut backtrace_string = String::new();
let max_line = 11;
for (frame, line) in frames.iter().zip(0..max_line) {
let symbol = frame.symbols().get(0).unwrap();
let mut name = String::new();
if let Some(name_value) = &symbol.name() {
let full_name = name_value.to_string();
let parts: Vec<&str> = full_name.split("::").collect();
if parts.len() >= 3 {
name = format!(
"{}::{}",
parts.get(parts.len() - 3).unwrap_or(&""),
parts.get(parts.len() - 2).unwrap_or(&""),
);
}
}
let mut filepath = String::new();
if let Some(filename) = &symbol.filename() {
let line_nr = &symbol.lineno().unwrap_or_default();
let path = filename.to_str().unwrap();
let (_, path) = path.split_at(path.find("df_st").unwrap_or(0));
filepath = format!(" => {}:{}", path, line_nr);
}
if line != 0 {
backtrace_string = format!("{}{}: {}{}\n", backtrace_string, line, name, filepath);
}
}
debug!(
"Backtrace for '{}' (see above): \n{}",
name, backtrace_string
);
}
pub trait ConvertingUtils {
fn to_uniform_name(&self) -> Option<String>;
}
impl ConvertingUtils for Option<String> {
fn to_uniform_name(&self) -> Option<String> {
match self {
Some(string_value) => {
let mut string_value = string_value.clone();
string_value = string_value.to_ascii_lowercase();
string_value = string_value.replace("_", " ");
Some(string_value)
}
None => None,
}
}
}
pub trait Filler<D, S>
where
D: Fillable + Debug,
S: Debug,
{
fn add_missing_data(&mut self, source: &S);
fn add_missing_data_indexed(&mut self, source: &S, _index: u64) {
self.add_missing_data(source);
}
fn never_replace_data(&mut self, source: &S)
where
Self: std::fmt::Debug,
{
warn!("Warning: `never_replace_data` is called for an object where\n\
this function is not implemented but still called. This function is part of the `Filler` trait.\n\
Consider calling `add_missing_data` instead.\n\
--------------------------------\n\
\tNot implemented for (combination): \n{:#?}\n&\n{:#?}\n\
--------------------------------",
self, source);
}
fn replace_data(&mut self, source: &S)
where
Self: std::fmt::Debug,
{
warn!("Warning: `replace_data` is called for an object where\n\
this function is not implemented but still called. This function is part of the `Filler` trait.\n\
Consider calling `add_missing_data` instead.\n\
--------------------------------\n\
\tNot implemented for (combination): \n{:#?}\n&\n{:#?}\n\
--------------------------------",
self, source);
}
fn check_mergeable(&self, source: &S) -> bool
where
Self: Debug + Default + PartialEq<Self>,
S: PartialEq<Self> + Debug,
{
if self == &(Self::default()) {
return true;
}
if source != self {
warn!(
"Warning: Items are not the same (not same identifiers)\n\
This will result in corrupted data. Stopping merging data.\n\
--------------------------------\n\
\tDifferent Identifiers: \n{:#?}\n!=\n{:#?}\n\
--------------------------------",
self, source
);
return false;
}
true
}
}
impl Fillable for i32 {}
impl Filler<i32, i32> for i32 {
fn add_missing_data(&mut self, source: &i32) {
*self = *source;
}
fn never_replace_data(&mut self, source: &i32) {
*self = *source;
}
fn replace_data(&mut self, source: &i32) {
*self = *source;
}
}
impl Filler<i32, Option<i32>> for i32 {
fn add_missing_data(&mut self, source: &Option<i32>) {
if let Some(value) = source {
*self = *value;
}
}
fn never_replace_data(&mut self, source: &Option<i32>) {
if let Some(value) = source {
*self = *value;
}
}
fn replace_data(&mut self, source: &Option<i32>) {
if let Some(value) = source {
*self = *value;
}
}
}
impl Fillable for u32 {}
impl Filler<u32, u32> for u32 {
fn add_missing_data(&mut self, source: &u32) {
*self = *source;
}
fn never_replace_data(&mut self, source: &u32) {
*self = *source;
}
fn replace_data(&mut self, source: &u32) {
*self = *source;
}
}
impl Fillable for u8 {}
impl Filler<u8, u8> for u8 {
fn add_missing_data(&mut self, source: &u8) {
*self = *source;
}
fn never_replace_data(&mut self, source: &u8) {
*self = *source;
}
fn replace_data(&mut self, source: &u8) {
*self = *source;
}
}
impl Fillable for bool {}
impl Filler<bool, bool> for bool {
fn add_missing_data(&mut self, source: &bool) {
*self = *source;
}
fn never_replace_data(&mut self, source: &bool) {
*self = *source;
}
fn replace_data(&mut self, source: &bool) {
*self = *source;
}
}
impl Filler<Option<bool>, Option<()>> for Option<bool> {
fn add_missing_data(&mut self, source: &Option<()>) {
*self = match source {
Some(_) => Some(true),
None => None,
};
}
fn never_replace_data(&mut self, source: &Option<()>) {
if self.is_some() {
return;
}
*self = match source {
Some(_) => Some(true),
None => None,
};
}
fn replace_data(&mut self, source: &Option<()>) {
*self = match source {
Some(_) => Some(true),
None => None,
};
}
}
impl Filler<Option<bool>, Option<String>> for Option<bool> {
fn add_missing_data(&mut self, source: &Option<String>) {
let result = if let Some(value) = &source {
match value.as_ref() {
"true" => true,
"false" => false,
"1" => true,
"0" => false,
_ => true,
}
} else {
false
};
*self = Some(result);
}
fn never_replace_data(&mut self, source: &Option<String>) {
if self.is_some() {
return;
}
let result = if let Some(value) = &source {
match value.as_ref() {
"true" => true,
"false" => false,
"1" => true,
"0" => false,
_ => true,
}
} else {
false
};
*self = Some(result);
}
fn replace_data(&mut self, source: &Option<String>) {
let result = if let Some(value) = &source {
match value.as_ref() {
"true" => true,
"false" => false,
"1" => true,
"0" => false,
_ => true,
}
} else {
false
};
*self = Some(result);
}
}
impl Fillable for String {}
impl Filler<String, String> for String {
fn add_missing_data(&mut self, source: &String) {
*self = source.clone();
}
fn never_replace_data(&mut self, source: &String) {
*self = source.clone();
}
fn replace_data(&mut self, source: &String) {
*self = source.clone();
}
}
impl<T> Fillable for Option<T> {}
impl<T> Fillable for Vec<T> {}
impl<T, R> Filler<Vec<T>, Vec<R>> for Vec<T>
where
T: Fillable + Filler<T, R> + Default + Debug,
R: PartialEq<T> + Debug,
{
fn add_missing_data(&mut self, source: &Vec<R>) {
for (index, item) in source.iter().enumerate() {
let mut found_object_in_self: Option<&mut T> = None;
for item2 in self.iter_mut() {
if item == item2 {
found_object_in_self = Some(item2);
break;
}
}
if let Some(item2) = found_object_in_self {
if item == item2 {
item2.add_missing_data_indexed(item, index as u64);
} else {
not_same_id(&item, &item2);
}
} else {
let mut new_item = T::default();
new_item.add_missing_data_indexed(item, index as u64);
self.push(new_item);
}
}
}
fn never_replace_data(&mut self, source: &Vec<R>) {
for item in source {
let mut found_object_in_self: Option<&mut T> = None;
for item2 in self.iter_mut() {
if item == item2 {
found_object_in_self = Some(item2);
break;
}
}
if let Some(item2) = found_object_in_self {
if item == item2 {
item2.never_replace_data(item);
} else {
not_same_id(&item, &item2);
}
} else {
let mut new_item = T::default();
new_item.never_replace_data(item);
self.push(new_item);
}
}
}
fn replace_data(&mut self, source: &Vec<R>) {
for item in source {
let mut found_object_in_self: Option<&mut T> = None;
for item2 in self.iter_mut() {
if item == item2 {
found_object_in_self = Some(item2);
break;
}
}
if let Some(item2) = found_object_in_self {
if item == item2 {
item2.replace_data(item);
} else {
not_same_id(&item, &item2);
}
} else {
let mut new_item = T::default();
new_item.replace_data(item);
self.push(new_item);
}
}
}
}
impl<T> Fillable for IndexMap<u64, T> {}
impl<T, R> Filler<IndexMap<u64, T>, IndexMap<u64, R>> for IndexMap<u64, T>
where
T: Fillable + Filler<T, R> + Default + Debug + Hash,
R: PartialEq<T> + Debug + Hash,
{
fn add_missing_data(&mut self, source: &IndexMap<u64, R>) {
for (index, item) in source {
let mut hasher = self.hasher().build_hasher();
item.hash(&mut hasher);
let hash = hasher.finish();
let found_object_in_self: Option<&mut T> = self.get_mut(&hash);
if let Some(item2) = found_object_in_self {
if item == item2 {
item2.add_missing_data_indexed(item, *index);
} else {
not_same_id(&item, &item2);
}
} else {
let mut new_item = T::default();
new_item.add_missing_data_indexed(item, *index);
let mut hasher = self.hasher().build_hasher();
new_item.hash(&mut hasher);
let hash = hasher.finish();
self.insert(hash, new_item);
}
}
}
fn never_replace_data(&mut self, source: &IndexMap<u64, R>) {
for (_index, item) in source {
let mut hasher = self.hasher().build_hasher();
item.hash(&mut hasher);
let hash = hasher.finish();
let found_object_in_self: Option<&mut T> = self.get_mut(&hash);
if let Some(item2) = found_object_in_self {
if item == item2 {
item2.never_replace_data(item);
} else {
not_same_id(&item, &item2);
}
} else {
let mut new_item = T::default();
new_item.never_replace_data(item);
let mut hasher = self.hasher().build_hasher();
new_item.hash(&mut hasher);
let hash = hasher.finish();
self.insert(hash, new_item);
}
}
}
fn replace_data(&mut self, source: &IndexMap<u64, R>) {
for (_index, item) in source {
let mut hasher = self.hasher().build_hasher();
item.hash(&mut hasher);
let hash = hasher.finish();
let found_object_in_self: Option<&mut T> = self.get_mut(&hash);
if let Some(item2) = found_object_in_self {
if item == item2 {
item2.replace_data(item);
} else {
not_same_id(&item, &item2);
}
} else {
let mut new_item = T::default();
new_item.replace_data(item);
let mut hasher = self.hasher().build_hasher();
new_item.hash(&mut hasher);
let hash = hasher.finish();
self.insert(hash, new_item);
}
}
}
}
impl<T> Fillable for HashSet<T> {}
impl<T, R> Filler<HashSet<T>, HashSet<R>> for HashSet<T>
where
T: Fillable + Filler<T, R> + Default + Debug + Eq + Hash,
R: PartialEq<T> + Debug,
{
fn add_missing_data(&mut self, source: &HashSet<R>) {
for item in source {
let mut new_item = T::default();
new_item.add_missing_data(item);
let found_object_in_self: Option<T> = self.take(&new_item);
if let Some(mut item2) = found_object_in_self {
if item == &item2 {
item2.add_missing_data(item);
self.insert(item2);
} else {
not_same_id(&item, &item2);
}
} else {
self.insert(new_item);
}
}
}
fn never_replace_data(&mut self, source: &HashSet<R>) {
for item in source {
let mut new_item = T::default();
new_item.never_replace_data(item);
let found_object_in_self: Option<T> = self.take(&new_item);
if let Some(mut item2) = found_object_in_self {
if item == &item2 {
item2.never_replace_data(item);
self.insert(item2);
} else {
not_same_id(&item, &item2);
}
} else {
self.insert(new_item);
}
}
}
fn replace_data(&mut self, source: &HashSet<R>) {
for item in source {
let mut new_item = T::default();
new_item.replace_data(item);
let found_object_in_self: Option<T> = self.take(&new_item);
if let Some(mut item2) = found_object_in_self {
if item == &item2 {
item2.replace_data(item);
self.insert(item2);
} else {
not_same_id(&item, &item2);
}
} else {
self.insert(new_item);
}
}
}
}
impl<T, R> Filler<IndexMap<u64, T>, Vec<R>> for IndexMap<u64, T>
where
T: Fillable + Filler<T, R> + Default + Debug + Hash,
R: PartialEq<T> + Debug + Hash,
{
fn add_missing_data(&mut self, source: &Vec<R>) {
for (index, item) in source.iter().enumerate() {
let mut hasher = self.hasher().build_hasher();
item.hash(&mut hasher);
let hash = hasher.finish();
let found_object_in_self: Option<&mut T> = self.get_mut(&hash);
if let Some(item2) = found_object_in_self {
if item == item2 {
item2.add_missing_data_indexed(item, index as u64);
} else {
not_same_id(&item, &item2);
}
} else {
let mut new_item = T::default();
new_item.add_missing_data_indexed(item, index as u64);
let mut hasher = self.hasher().build_hasher();
new_item.hash(&mut hasher);
let hash = hasher.finish();
self.insert(hash, new_item);
}
}
}
fn never_replace_data(&mut self, source: &Vec<R>) {
for item in source {
let mut hasher = self.hasher().build_hasher();
item.hash(&mut hasher);
let hash = hasher.finish();
let found_object_in_self: Option<&mut T> = self.get_mut(&hash);
if let Some(item2) = found_object_in_self {
if item == item2 {
item2.never_replace_data(item);
} else {
not_same_id(&item, &item2);
}
} else {
let mut new_item = T::default();
new_item.never_replace_data(item);
let mut hasher = self.hasher().build_hasher();
new_item.hash(&mut hasher);
let hash = hasher.finish();
self.insert(hash, new_item);
}
}
}
fn replace_data(&mut self, source: &Vec<R>) {
for item in source {
let mut hasher = self.hasher().build_hasher();
item.hash(&mut hasher);
let hash = hasher.finish();
let found_object_in_self: Option<&mut T> = self.get_mut(&hash);
if let Some(item2) = found_object_in_self {
if item == item2 {
item2.replace_data(item);
} else {
not_same_id(&item, &item2);
}
} else {
let mut new_item = T::default();
new_item.replace_data(item);
let mut hasher = self.hasher().build_hasher();
new_item.hash(&mut hasher);
let hash = hasher.finish();
self.insert(hash, new_item);
}
}
}
}
impl<T, R> Filler<IndexMap<u64, T>, HashSet<R>> for IndexMap<u64, T>
where
T: Fillable + Filler<T, R> + Default + Debug + Hash,
R: PartialEq<T> + Debug + Hash,
{
fn add_missing_data(&mut self, source: &HashSet<R>) {
for (index, item) in source.iter().enumerate() {
let mut hasher = self.hasher().build_hasher();
item.hash(&mut hasher);
let hash = hasher.finish();
let found_object_in_self: Option<&mut T> = self.get_mut(&hash);
if let Some(item2) = found_object_in_self {
if item == item2 {
item2.add_missing_data_indexed(item, index as u64);
} else {
not_same_id(&item, &item2);
}
} else {
let mut new_item = T::default();
new_item.add_missing_data_indexed(item, index as u64);
let mut hasher = self.hasher().build_hasher();
new_item.hash(&mut hasher);
let hash = hasher.finish();
self.insert(hash, new_item);
}
}
}
fn never_replace_data(&mut self, source: &HashSet<R>) {
for item in source {
let mut hasher = self.hasher().build_hasher();
item.hash(&mut hasher);
let hash = hasher.finish();
let found_object_in_self: Option<&mut T> = self.get_mut(&hash);
if let Some(item2) = found_object_in_self {
if item == item2 {
item2.never_replace_data(item);
} else {
not_same_id(&item, &item2);
}
} else {
let mut new_item = T::default();
new_item.never_replace_data(item);
let mut hasher = self.hasher().build_hasher();
new_item.hash(&mut hasher);
let hash = hasher.finish();
self.insert(hash, new_item);
}
}
}
fn replace_data(&mut self, source: &HashSet<R>) {
for item in source {
let mut hasher = self.hasher().build_hasher();
item.hash(&mut hasher);
let hash = hasher.finish();
let found_object_in_self: Option<&mut T> = self.get_mut(&hash);
if let Some(item2) = found_object_in_self {
if item == item2 {
item2.replace_data(item);
} else {
not_same_id(&item, &item2);
}
} else {
let mut new_item = T::default();
new_item.replace_data(item);
let mut hasher = self.hasher().build_hasher();
new_item.hash(&mut hasher);
let hash = hasher.finish();
self.insert(hash, new_item);
}
}
}
}
impl<T, R> Filler<Option<T>, Option<R>> for Option<T>
where
T: Fillable + Filler<T, R> + Default + Debug,
R: PartialEq<T> + Debug + Clone,
{
fn add_missing_data(&mut self, source: &Option<R>) {
let value = match source {
#[allow(clippy::clone_on_copy)]
Some(x) => x.clone(),
None => return,
};
match self {
Some(x) => {
if value != *x {
not_same_data(&x, &value);
} else {
x.add_missing_data(&value);
}
}
None => {
let mut new_value = T::default();
new_value.add_missing_data(&value);
*self = Some(new_value);
}
}
}
fn never_replace_data(&mut self, source: &Option<R>) {
let value = match source {
#[allow(clippy::clone_on_copy)]
Some(x) => x.clone(),
None => return,
};
match self {
Some(_x) => {
}
None => {
let mut new_value = T::default();
new_value.never_replace_data(&value);
*self = Some(new_value);
}
}
}
fn replace_data(&mut self, source: &Option<R>) {
let value = match source {
#[allow(clippy::clone_on_copy)]
Some(x) => x.clone(),
None => return,
};
match self {
Some(x) => {
x.replace_data(&value);
}
None => {
let mut new_value = T::default();
new_value.replace_data(&value);
*self = Some(new_value);
}
}
}
}
impl<T, R> Filler<Vec<T>, Option<Vec<R>>> for Vec<T>
where
T: Fillable + Filler<T, R> + Default + Debug,
R: PartialEq<T> + Debug,
{
fn add_missing_data(&mut self, source: &Option<Vec<R>>) {
let value = match source {
#[allow(clippy::clone_on_copy)]
Some(x) => x,
None => return,
};
self.add_missing_data(value);
}
fn never_replace_data(&mut self, source: &Option<Vec<R>>) {
let value = match source {
#[allow(clippy::clone_on_copy)]
Some(x) => x,
None => return,
};
self.never_replace_data(value);
}
fn replace_data(&mut self, source: &Option<Vec<R>>) {
let value = match source {
#[allow(clippy::clone_on_copy)]
Some(x) => x,
None => return,
};
self.replace_data(value);
}
}
impl<T, R> Filler<IndexMap<u64, T>, Option<Vec<R>>> for IndexMap<u64, T>
where
T: Fillable + Filler<T, R> + Default + Debug + Hash,
R: PartialEq<T> + Debug + Hash,
{
fn add_missing_data(&mut self, source: &Option<Vec<R>>) {
let value = match source {
#[allow(clippy::clone_on_copy)]
Some(x) => x,
None => return,
};
self.add_missing_data(value);
}
fn never_replace_data(&mut self, source: &Option<Vec<R>>) {
let value = match source {
#[allow(clippy::clone_on_copy)]
Some(x) => x,
None => return,
};
self.never_replace_data(value);
}
fn replace_data(&mut self, source: &Option<Vec<R>>) {
let value = match source {
#[allow(clippy::clone_on_copy)]
Some(x) => x,
None => return,
};
self.replace_data(value);
}
}