use hashbrown::{hash_map::RawEntryMut as HBRawEntryMut, HashMap as HBHashMap};
use serde::{Deserialize, Serialize};
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::fmt;
use std::vec::Vec;
use super::localize::CommaFormat;
use super::location::Location;
#[cfg(feature = "experimental")]
use super::posf32::deserialize_positive_f32;
use super::posf32::{PositiveF32, PositiveF32Error};
#[cfg(test)]
use crate::engines::niseci::linear_regression::Point;
#[cfg(feature = "lessclone")]
pub mod lessclone;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SpecieNISECI {
#[deprecated(note = "v0.2 will drop visibility. Consider using self.id() instead")]
pub id: String,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.nome() instead")]
pub nome: String,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.tipo_autoctono() instead")]
pub tipo_autoctono: u8,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.tipo_alloctono() instead")]
pub tipo_alloctono: u8,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.specie_attesa() instead")]
pub specie_attesa: bool,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.cl_soglia_1() instead")]
pub cl_soglia1: u32, #[deprecated(note = "v0.2 will drop visibility. Consider using self.cl_soglia_2() instead")]
pub cl_soglia2: u32, #[deprecated(note = "v0.2 will drop visibility. Consider using self.cl_soglia_3() instead")]
pub cl_soglia3: u32, #[deprecated(note = "v0.2 will drop visibility. Consider using self.cl_soglia_4() instead")]
pub cl_soglia4: u32, #[deprecated(
note = "v0.2 will drop visibility. Consider using self.ad_juv_soglia_1() instead"
)]
pub ad_juv_soglia1: f32,
#[deprecated(
note = "v0.2 will drop visibility. Consider using self.ad_juv_soglia_2() instead"
)]
pub ad_juv_soglia2: f32,
#[deprecated(
note = "v0.2 will drop visibility. Consider using self.ad_juv_soglia_3() instead"
)]
pub ad_juv_soglia3: f32,
#[deprecated(
note = "v0.2 will drop visibility. Consider using self.ad_juv_soglia_4() instead"
)]
pub ad_juv_soglia4: f32,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.dens_soglia_1() instead")]
pub dens_soglia1: f32,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.dens_soglia_2() instead")]
pub dens_soglia2: f32,
}
impl fmt::Display for SpecieNISECI {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let specie_attesa_str = match self.specie_attesa() {
true => "SI",
false => "NO",
};
let string_representation = format!(
"{}; {}; {}; {}; {}",
self.id(),
self.nome(),
self.tipo_autoctono(),
self.tipo_alloctono(),
specie_attesa_str
);
write!(f, "{}", string_representation)
}
}
impl SpecieNISECI {
#[cfg(test)]
pub(crate) fn new(
id: &str,
nome: &str,
tipo_autoctono: u8,
tipo_alloctono: u8,
specie_attesa: bool,
cl_soglia_1: u32,
cl_soglia_2: u32,
cl_soglia_3: u32,
cl_soglia_4: u32,
ad_juv_soglia_1: f32,
ad_juv_soglia_2: f32,
ad_juv_soglia_3: f32,
ad_juv_soglia_4: f32,
dens_soglia_1: f32,
dens_soglia_2: f32,
) -> Self {
#[expect(deprecated)]
SpecieNISECI {
id: id.to_string(),
nome: nome.to_string(),
tipo_autoctono,
tipo_alloctono,
specie_attesa,
cl_soglia1: cl_soglia_1,
cl_soglia2: cl_soglia_2,
cl_soglia3: cl_soglia_3,
cl_soglia4: cl_soglia_4,
ad_juv_soglia1: ad_juv_soglia_1,
ad_juv_soglia2: ad_juv_soglia_2,
ad_juv_soglia3: ad_juv_soglia_3,
ad_juv_soglia4: ad_juv_soglia_4,
dens_soglia1: dens_soglia_1,
dens_soglia2: dens_soglia_2,
}
}
#[deprecated(note = "v0.2 will drop visibility. Consider using SpecieNISECI::new() instead")]
pub fn new_dummy_specie() -> SpecieNISECI {
#[expect(deprecated)]
SpecieNISECI {
id: "0".to_string(),
nome: "dummy".to_string(),
tipo_autoctono: 0,
tipo_alloctono: 0,
specie_attesa: true,
cl_soglia1: 1, cl_soglia2: 2, cl_soglia3: 3, cl_soglia4: 4,
ad_juv_soglia1: 0.1,
ad_juv_soglia2: 0.2,
ad_juv_soglia3: 0.3,
ad_juv_soglia4: 0.4,
dens_soglia1: 0.5,
dens_soglia2: 0.9,
}
}
#[inline(always)]
pub(crate) fn id(&self) -> &str {
#[expect(deprecated)]
&self.id
}
pub(crate) fn nome(&self) -> &str {
#[expect(deprecated)]
&self.nome
}
#[inline(always)]
pub(crate) fn specie_attesa(&self) -> bool {
#[expect(deprecated)]
self.specie_attesa
}
#[inline(always)]
pub(crate) fn tipo_autoctono(&self) -> u8 {
#[expect(deprecated)]
self.tipo_autoctono
}
#[inline(always)]
pub(crate) fn tipo_alloctono(&self) -> u8 {
#[expect(deprecated)]
self.tipo_alloctono
}
#[inline(always)]
pub(crate) fn cl_soglia_1(&self) -> u32 {
#[expect(deprecated)]
self.cl_soglia1
}
#[inline(always)]
pub(crate) fn cl_soglia_2(&self) -> u32 {
#[expect(deprecated)]
self.cl_soglia2
}
#[inline(always)]
pub(crate) fn cl_soglia_3(&self) -> u32 {
#[expect(deprecated)]
self.cl_soglia3
}
#[inline(always)]
pub(crate) fn cl_soglia_4(&self) -> u32 {
#[expect(deprecated)]
self.cl_soglia4
}
#[inline(always)]
pub(crate) fn ad_juv_soglia_1(&self) -> f32 {
#[expect(deprecated)]
self.ad_juv_soglia1
}
#[inline(always)]
pub(crate) fn ad_juv_soglia_2(&self) -> f32 {
#[expect(deprecated)]
self.ad_juv_soglia2
}
#[inline(always)]
pub(crate) fn ad_juv_soglia_3(&self) -> f32 {
#[expect(deprecated)]
self.ad_juv_soglia3
}
#[inline(always)]
pub(crate) fn ad_juv_soglia_4(&self) -> f32 {
#[expect(deprecated)]
self.ad_juv_soglia4
}
#[inline(always)]
pub(crate) fn dens_soglia_1(&self) -> f32 {
#[expect(deprecated)]
self.dens_soglia1
}
#[cfg(test)]
pub(crate) fn set_dens_soglia_1(&mut self, val: f32) {
#[expect(deprecated)]
{
self.dens_soglia1 = val;
}
}
#[inline(always)]
pub(crate) fn dens_soglia_2(&self) -> f32 {
#[expect(deprecated)]
self.dens_soglia2
}
#[cfg(test)]
pub(crate) fn set_dens_soglia_2(&mut self, val: f32) {
#[expect(deprecated)]
{
self.dens_soglia2 = val;
}
}
}
pub(crate) type IdSpecieNISECI = u32;
#[derive(Debug, Clone, Serialize)]
pub(crate) struct StoreSpecieNISECI {
values: Vec<SpecieNISECI>,
}
impl StoreSpecieNISECI {
fn new() -> Self {
Self { values: Vec::new() }
}
#[inline(always)]
fn insert(&mut self, id: IdSpecieNISECI, value: SpecieNISECI) {
debug_assert_eq!(
id as usize,
self.values.len(),
"Ids are supposed to be dense"
);
self.values.push(value);
}
#[inline(always)]
fn get(&self, id: IdSpecieNISECI) -> Option<&SpecieNISECI> {
self.values.get(id as usize)
}
}
#[derive(Debug, Clone, Serialize)]
pub(crate) struct InternerSpecieNISECI {
map: HBHashMap<String, IdSpecieNISECI>,
store: StoreSpecieNISECI,
next_id: IdSpecieNISECI,
}
impl InternerSpecieNISECI {
pub(crate) fn new() -> Self {
Self {
map: HBHashMap::new(),
next_id: 0,
store: StoreSpecieNISECI::new(),
}
}
#[inline(always)]
pub(crate) fn contains_id(&self, s: &str) -> bool {
self.map.contains_key(s)
}
#[inline(always)]
pub(crate) fn contains_plain_id(&self, id: IdSpecieNISECI) -> bool {
self.store.get(id).is_some()
}
#[inline(always)]
pub(crate) fn get(&self, s: &str) -> Option<&SpecieNISECI> {
self.map.get(s).and_then(|k| self.store.get(*k))
}
#[inline(always)]
pub(crate) fn get_by_id(&self, id: IdSpecieNISECI) -> Option<&SpecieNISECI> {
self.store.get(id)
}
#[inline(always)]
pub(crate) fn get_by_str_id(&self, s: &str) -> Option<IdSpecieNISECI> {
self.map.get(s).copied()
}
#[inline(always)]
pub(crate) fn intern(&mut self, s: &str, val: SpecieNISECI) -> IdSpecieNISECI {
match self.map.raw_entry_mut().from_key(s) {
HBRawEntryMut::Occupied(entry) => *entry.get(),
HBRawEntryMut::Vacant(entry) => {
let id = self.next_id;
self.next_id += 1;
entry.insert(s.to_owned(), id);
self.store.insert(id, val);
id
}
}
}
}
impl From<Vec<SpecieNISECI>> for InternerSpecieNISECI {
fn from(val: Vec<SpecieNISECI>) -> Self {
let mut res = Self::new();
for v in val {
res.intern(&v.id().to_string(), v);
}
res
}
}
#[derive(Clone, Serialize)]
#[cfg_attr(feature = "experimental", derive(Deserialize))]
#[serde(deny_unknown_fields)]
pub struct RiferimentoNISECI {
#[deprecated(
note = "v0.2 will change visibility.\nConsider using self.into() for owned conversion, &self for borrowed iteration, RiferimentoNISECI::new() to construct"
)]
pub elenco_specie: Vec<SpecieNISECI>,
map_ids: InternerSpecieNISECI,
}
impl fmt::Display for RiferimentoNISECI {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut string_representation = "RiferimentoNISECI: {".to_string();
for s in self {
string_representation = format!("{string_representation}\n {{{s}}},");
}
string_representation = format!("{string_representation}\n}}");
write!(f, "{}", string_representation)
}
}
impl RiferimentoNISECI {
pub fn new(elenco_specie: Vec<SpecieNISECI>) -> Self {
let mut interner = InternerSpecieNISECI::new();
for rec in &elenco_specie {
interner.intern(rec.id(), rec.clone());
}
#[allow(deprecated)]
Self {
elenco_specie,
map_ids: interner,
}
}
pub(crate) fn new_from_map(map_ids: InternerSpecieNISECI) -> Self {
let mut elenco_specie = Vec::new();
for s in map_ids.store.values.iter() {
elenco_specie.push(s.clone());
}
#[allow(deprecated)]
Self {
elenco_specie,
map_ids,
}
}
#[inline(always)]
pub fn contains_id(&self, id: &str) -> bool {
self.map_ids.contains_id(id)
}
#[inline(always)]
pub fn contains_plain_id(&self, id: IdSpecieNISECI) -> bool {
self.map_ids.contains_plain_id(id)
}
#[inline(always)]
pub fn get_ref_by_id(&self, id: &str) -> Option<&SpecieNISECI> {
self.map_ids.get(id)
}
#[inline(always)]
pub fn get_ref_by_plain_id(&self, id: IdSpecieNISECI) -> Option<&SpecieNISECI> {
self.map_ids.get_by_id(id)
}
#[inline(always)]
pub fn get_inner_id(&self, id: &str) -> Option<IdSpecieNISECI> {
self.map_ids.get_by_str_id(id)
}
pub fn to_csv_intermediates_joined(
&self,
intermediates: &ValoriIntermediNISECI,
comma_csv_delimiter: bool,
) -> String {
intermediates.to_csv_joined(self, comma_csv_delimiter)
}
}
impl From<RiferimentoNISECI> for Vec<SpecieNISECI> {
fn from(val: RiferimentoNISECI) -> Self {
#[allow(deprecated)]
val.elenco_specie
}
}
impl<'a> IntoIterator for &'a RiferimentoNISECI {
type Item = &'a SpecieNISECI;
type IntoIter = std::slice::Iter<'a, SpecieNISECI>;
fn into_iter(self) -> Self::IntoIter {
self.map_ids.store.values.iter()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RecordNISECI {
specie: SpecieNISECI,
passaggio_cattura: u8,
lunghezza: u32,
peso: f32, }
impl fmt::Display for RecordNISECI {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let string_representation = format!("RecordNISECI: {{ specie: {{{}}}, passaggio_cattura {{{}}}, lunghezza: {{{}}}, peso: {{{}}}",
self.specie(), self.passaggio_cattura(), self.lunghezza(), self.peso());
write!(f, "{}", string_representation)
}
}
impl RecordNISECI {
pub fn new(specie: &SpecieNISECI, passaggio_cattura: u8, lunghezza: u32, peso: f32) -> Self {
Self {
specie: specie.clone(),
passaggio_cattura,
lunghezza,
peso,
}
}
#[inline(always)]
pub fn passaggio_cattura(&self) -> u8 {
self.passaggio_cattura
}
#[inline(always)]
pub fn lunghezza(&self) -> u32 {
self.lunghezza
}
#[inline(always)]
pub fn peso(&self) -> f32 {
self.peso
}
#[inline(always)]
pub(crate) fn specie(&self) -> &SpecieNISECI {
&self.specie
}
#[inline(always)]
pub(crate) fn id(&self) -> &str {
self.specie.id()
}
#[inline(always)]
pub(crate) fn tipo_autoctono(&self) -> u8 {
self.specie.tipo_autoctono()
}
#[inline(always)]
pub(crate) fn tipo_alloctono(&self) -> u8 {
self.specie.tipo_alloctono()
}
#[inline(always)]
pub(crate) fn specie_attesa(&self) -> bool {
self.specie.specie_attesa()
}
#[inline(always)]
pub(crate) fn cl_soglia_1(&self) -> u32 {
self.specie.cl_soglia_1()
}
#[inline(always)]
pub(crate) fn cl_soglia_2(&self) -> u32 {
self.specie.cl_soglia_2()
}
#[inline(always)]
pub(crate) fn cl_soglia_3(&self) -> u32 {
self.specie.cl_soglia_3()
}
#[inline(always)]
pub(crate) fn cl_soglia_4(&self) -> u32 {
self.specie.cl_soglia_4()
}
#[inline(always)]
pub(crate) fn ad_juv_soglia_1(&self) -> f32 {
self.specie.ad_juv_soglia_1()
}
#[inline(always)]
pub(crate) fn ad_juv_soglia_2(&self) -> f32 {
self.specie.ad_juv_soglia_2()
}
#[inline(always)]
pub(crate) fn ad_juv_soglia_3(&self) -> f32 {
self.specie.ad_juv_soglia_3()
}
#[inline(always)]
pub(crate) fn ad_juv_soglia_4(&self) -> f32 {
self.specie.ad_juv_soglia_4()
}
#[inline(always)]
pub fn dens_soglia_1(&self) -> f32 {
self.specie.dens_soglia_1()
}
#[inline(always)]
pub fn dens_soglia_2(&self) -> f32 {
self.specie.dens_soglia_2()
}
}
#[derive(Clone, Serialize)]
#[cfg_attr(feature = "experimental", derive(Deserialize))]
#[serde(deny_unknown_fields)]
pub struct CampionamentoNISECI {
#[deprecated(
note = "v0.2 will change visibility.\nConsider using self.into() for owned conversion, &self for borrowed iteration, CampionamentoNISECI::new() to construct"
)]
pub campionamento: Vec<RecordNISECI>,
}
impl fmt::Display for CampionamentoNISECI {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut string_representation = "CampionaNISECI: {".to_string();
for r in self {
string_representation = format!("{string_representation}\n {{{r}}},");
}
string_representation = format!("{string_representation}\n}}");
write!(f, "{}", string_representation)
}
}
impl CampionamentoNISECI {
#[cfg(test)]
pub fn fishes_for_every_passage(&self) -> Vec<Point<i32>> {
let mut max_pass = 0;
for record in self {
if record.passaggio_cattura() > max_pass {
max_pass = record.passaggio_cattura();
}
}
let mut passaggi: Vec<i32> = vec![0; max_pass as usize];
for record in self {
passaggi[(record.passaggio_cattura() - 1) as usize] += 1;
}
let mut tot = 0;
let mut pass_sum: Vec<Point<i32>> = Vec::with_capacity(max_pass as usize);
for pass in passaggi.iter() {
tot += pass;
pass_sum.push(Point::new(tot, *pass));
}
pass_sum
}
pub fn new(campionamento: Vec<RecordNISECI>) -> Self {
#[allow(deprecated)]
Self { campionamento }
}
pub fn get_numero_pesci_alieni_e_indigeni(&self) -> AlieniIndigeni {
let mut alieni_indigeni = AlieniIndigeni {
#[expect(deprecated)]
alieni: 0,
#[expect(deprecated)]
indigeni: 0,
};
for pesce in self {
if pesce.tipo_alloctono() > 0 && pesce.tipo_alloctono() <= 3 {
#[expect(deprecated)]
{
alieni_indigeni.alieni += 1;
}
} else if pesce.tipo_autoctono() == 1 || pesce.tipo_autoctono() == 2 {
#[expect(deprecated)]
{
alieni_indigeni.indigeni += 1;
}
}
}
alieni_indigeni
}
pub fn get_tot_specie_autoctone_attese(&self) -> usize {
let mut map: HashMap<String, bool> = HashMap::new();
for cattura in self {
if cattura.specie_attesa()
&& (cattura.tipo_autoctono() == 1 || cattura.tipo_autoctono() == 2)
{
match map.entry(cattura.id().to_string()) {
Entry::Occupied(_) => {}
Entry::Vacant(entry) => {
entry.insert(true);
}
};
}
}
map.len()
}
}
impl From<CampionamentoNISECI> for Vec<RecordNISECI> {
fn from(val: CampionamentoNISECI) -> Self {
#[allow(deprecated)]
val.campionamento
}
}
impl<'a> IntoIterator for &'a CampionamentoNISECI {
type Item = &'a RecordNISECI;
type IntoIter = std::slice::Iter<'a, RecordNISECI>;
fn into_iter(self) -> Self::IntoIter {
#[allow(deprecated)]
self.campionamento.iter()
}
}
pub struct AlieniIndigeni {
#[deprecated(note = "v0.2 will drop visibility. Consider using self.alieni() instead")]
pub alieni: u32,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.indigeni() instead")]
pub indigeni: u32,
}
impl AlieniIndigeni {
#[inline(always)]
pub fn alieni(&self) -> u32 {
#[expect(deprecated)]
self.alieni
}
#[inline(always)]
pub fn indigeni(&self) -> u32 {
#[expect(deprecated)]
self.indigeni
}
}
#[derive(Copy, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub enum TipoComunitaNISECI {
Redatta,
Recuperata,
Dm260_2010,
AffinataDalMase,
}
impl fmt::Display for TipoComunitaNISECI {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let string_representation = match *self {
TipoComunitaNISECI::Redatta => "Redatta dall'operatore",
TipoComunitaNISECI::Recuperata => "Recuperata da fonti bibliografiche",
TipoComunitaNISECI::Dm260_2010 => "DM 260/2010",
TipoComunitaNISECI::AffinataDalMase => "Affinata dal Mase",
};
write!(f, "{}", string_representation)
}
}
impl TryFrom<i32> for TipoComunitaNISECI {
type Error = ();
fn try_from(v: i32) -> Result<Self, Self::Error> {
match v {
x if x == TipoComunitaNISECI::Redatta as i32 => Ok(TipoComunitaNISECI::Redatta),
x if x == TipoComunitaNISECI::Recuperata as i32 => Ok(TipoComunitaNISECI::Recuperata),
x if x == TipoComunitaNISECI::Dm260_2010 as i32 => Ok(TipoComunitaNISECI::Dm260_2010),
x if x == TipoComunitaNISECI::AffinataDalMase as i32 => {
Ok(TipoComunitaNISECI::AffinataDalMase)
}
_ => Err(()),
}
}
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ComunitaNISECI {
#[deprecated(note = "v0.2 will drop visibility. Consider using self.tipo()")]
pub tipo: TipoComunitaNISECI,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.fonte()")]
pub fonte: Option<String>,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.num_protocollo()")]
pub numero_protocollo: Option<String>,
}
impl fmt::Display for ComunitaNISECI {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let string_representation = match self.tipo() {
TipoComunitaNISECI::Redatta | TipoComunitaNISECI::Dm260_2010 => {
format!("Comunita di Riferimento: tipo: {} ", self.tipo())
}
TipoComunitaNISECI::Recuperata => {
if let Some(fonte) = self.fonte() {
format!(
"Comunita di Riferimento: tipo: {}, fonte: {}",
self.tipo(),
fonte
)
} else {
format!(
"Comunita di Riferimento: tipo: {}, fonte: MANCANTE",
self.tipo()
)
}
}
TipoComunitaNISECI::AffinataDalMase => {
if let Some(num_proto) = self.num_protocollo() {
format!(
"Comunita di Riferimento: tipo: {}, numero_protocollo: {}",
self.tipo(),
num_proto
)
} else {
format!(
"Comunita di Riferimento: tipo: {}, numero_protocollo: MANCANTE",
self.tipo()
)
}
}
};
write!(f, "{}", string_representation)
}
}
impl ComunitaNISECI {
pub fn new(
tipo: TipoComunitaNISECI,
fonte: Option<String>,
num_protocollo: Option<String>,
) -> Self {
Self {
#[expect(deprecated)]
tipo,
#[expect(deprecated)]
fonte,
#[expect(deprecated)]
numero_protocollo: num_protocollo,
}
}
#[inline(always)]
pub fn tipo(&self) -> TipoComunitaNISECI {
#[expect(deprecated)]
self.tipo
}
#[inline(always)]
pub fn fonte(&self) -> Option<&str> {
#[expect(deprecated)]
self.fonte.as_deref()
}
#[inline(always)]
pub fn num_protocollo(&self) -> Option<&str> {
#[expect(deprecated)]
self.numero_protocollo.as_deref()
}
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub enum AreaNISECI {
Alpina,
Mediterranea,
}
impl fmt::Display for AreaNISECI {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let string_representation = match *self {
AreaNISECI::Alpina => "Area NISECI: Alpina".to_string(),
AreaNISECI::Mediterranea => "Area NISECI: Mediterranea".to_string(),
};
write!(f, "{}", string_representation)
}
}
impl TryFrom<i32> for AreaNISECI {
type Error = ();
fn try_from(v: i32) -> Result<Self, Self::Error> {
match v {
x if x == AreaNISECI::Alpina as i32 => Ok(AreaNISECI::Alpina),
x if x == AreaNISECI::Mediterranea as i32 => Ok(AreaNISECI::Mediterranea),
_ => Err(()),
}
}
}
#[derive(Clone)]
pub struct AnagraficaNISECIDraft {
pub comunita: ComunitaNISECI,
pub codice_stazione: String,
pub date_string: String, pub area: AreaNISECI,
pub corpo_idrico: String,
pub bacino_appartenenza: String,
pub idro_eco_regione: IdroEcoRegioneNISECI,
pub posizione: Location,
pub lunghezza_media_stazione: String,
pub larghezza_media_stazione: String,
}
#[derive(Clone, Serialize)]
#[cfg_attr(feature = "experimental", derive(Deserialize))]
#[serde(deny_unknown_fields)]
pub struct AnagraficaNISECI {
pub comunita: ComunitaNISECI,
pub codice_stazione: String,
pub date_string: String, pub area: AreaNISECI,
pub corpo_idrico: String,
pub bacino_appartenenza: String,
pub idro_eco_regione: IdroEcoRegioneNISECI,
pub posizione: Location,
#[deprecated(
note = "v0.2 will change visibility.\nConsider using self.get_lunghezza_media(), self.set_lunghezza_media(), AnagraficaNISECI::new() to construct"
)]
#[serde(deserialize_with = "deserialize_positive_f32")]
pub lunghezza_media_stazione: f32,
#[deprecated(
note = "v0.2 will change visibility.\nConsider using self.get_larghezza_media(), self.set_larghezza_media(), AnagraficaNISECI::new() to construct"
)]
#[serde(deserialize_with = "deserialize_positive_f32")]
pub larghezza_media_stazione: f32,
}
impl AnagraficaNISECI {
#[allow(clippy::too_many_arguments)]
pub fn new(
comunita: ComunitaNISECI,
codice_stazione: String,
date_string: String,
area: AreaNISECI,
corpo_idrico: String,
bacino_appartenenza: String,
idro_eco_regione: IdroEcoRegioneNISECI,
posizione: Location,
lunghezza_media_stazione: PositiveF32,
larghezza_media_stazione: PositiveF32,
) -> Self {
Self {
comunita,
codice_stazione,
date_string,
area,
corpo_idrico,
bacino_appartenenza,
idro_eco_regione,
posizione,
#[allow(deprecated)]
lunghezza_media_stazione: *lunghezza_media_stazione,
#[allow(deprecated)]
larghezza_media_stazione: *larghezza_media_stazione,
}
}
pub fn get_lunghezza_media(&self) -> f32 {
#[allow(deprecated)]
self.lunghezza_media_stazione
}
pub fn set_lunghezza_media(&mut self, val: f32) -> Result<(), PositiveF32Error> {
if !val.is_finite() {
return Err(PositiveF32Error::NotFinite);
}
if val <= 0.0 {
return Err(PositiveF32Error::NotPositive);
}
#[allow(deprecated)]
{
self.lunghezza_media_stazione = val;
}
Ok(())
}
pub fn get_larghezza_media(&self) -> f32 {
#[allow(deprecated)]
self.larghezza_media_stazione
}
pub fn set_larghezza_media(&mut self, val: f32) -> Result<(), PositiveF32Error> {
if !val.is_finite() {
return Err(PositiveF32Error::NotFinite);
}
if val <= 0.0 {
return Err(PositiveF32Error::NotPositive);
}
#[allow(deprecated)]
{
self.larghezza_media_stazione = val;
}
Ok(())
}
}
impl fmt::Display for AnagraficaNISECI {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let string_representation = format!("AnagraficaNISECI: {{ comunita: {{{}}}, codice_stazione {{{}}}, area: {{{}}}, corpo_idrico: {{{}}}, bacino_appartenenza: {{{}}}, idro_eco_regione: {{{}}}, posizione: {{{}}}, lunghezza_stazione: {{{}}}, larghezza_stazione: {{{}}} }}",
self.comunita, self.codice_stazione, self.area, self.corpo_idrico, self.bacino_appartenenza, self.idro_eco_regione, self.posizione, self.get_lunghezza_media(), self.get_larghezza_media());
write!(f, "{}", string_representation)
}
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub enum IdroEcoRegioneNISECI {
AlpiOccidentali,
PrealpiDolomiti,
AlpiCentroOrientali,
AlpiMeridionali,
Monferrato,
PianuraPadana,
Carso,
AppenninoPiemontese,
AlpiMediterranee,
AppenninoSettentrionale,
Toscana,
CostaAdriatica,
AppenninoCentrale,
RomaViterbese,
BassoLazio,
Vesuvio,
BasilicataTavoliere,
PugliaCarsica,
AppenninoMeridionale,
Sicilia,
Sardegna,
}
impl fmt::Display for IdroEcoRegioneNISECI {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let string_representation = match *self {
IdroEcoRegioneNISECI::AlpiOccidentali => "Alpi Occidentali",
IdroEcoRegioneNISECI::PrealpiDolomiti => "Prealpi Dolomiti",
IdroEcoRegioneNISECI::AlpiCentroOrientali => "Alpi Centro-orientali",
IdroEcoRegioneNISECI::AlpiMeridionali => "Alpi Meridionali",
IdroEcoRegioneNISECI::Monferrato => "Monferrato",
IdroEcoRegioneNISECI::PianuraPadana => "Pianura Padana",
IdroEcoRegioneNISECI::Carso => "Carso",
IdroEcoRegioneNISECI::AppenninoPiemontese => "Appennino Piemontese",
IdroEcoRegioneNISECI::AlpiMediterranee => "Alpi Mediterranee",
IdroEcoRegioneNISECI::AppenninoSettentrionale => "Appennino Settentrionale",
IdroEcoRegioneNISECI::Toscana => "Toscana",
IdroEcoRegioneNISECI::CostaAdriatica => "Costa Adriatica",
IdroEcoRegioneNISECI::AppenninoCentrale => "Appennino Centrale",
IdroEcoRegioneNISECI::RomaViterbese => "Roma-Viterbese",
IdroEcoRegioneNISECI::BassoLazio => "Basso Lazio",
IdroEcoRegioneNISECI::Vesuvio => "Vesuvio",
IdroEcoRegioneNISECI::BasilicataTavoliere => "Basilicata Tavoliere",
IdroEcoRegioneNISECI::PugliaCarsica => "Puglia Carsica",
IdroEcoRegioneNISECI::AppenninoMeridionale => "Appennino Meridionale",
IdroEcoRegioneNISECI::Sicilia => "Sicilia",
IdroEcoRegioneNISECI::Sardegna => "Sardegna",
};
write!(f, "{}", string_representation)
}
}
impl TryFrom<i32> for IdroEcoRegioneNISECI {
type Error = ();
fn try_from(v: i32) -> Result<Self, Self::Error> {
match v {
x if x == IdroEcoRegioneNISECI::AlpiOccidentali as i32 => {
Ok(IdroEcoRegioneNISECI::AlpiOccidentali)
}
x if x == IdroEcoRegioneNISECI::PrealpiDolomiti as i32 => {
Ok(IdroEcoRegioneNISECI::PrealpiDolomiti)
}
x if x == IdroEcoRegioneNISECI::AlpiCentroOrientali as i32 => {
Ok(IdroEcoRegioneNISECI::AlpiCentroOrientali)
}
x if x == IdroEcoRegioneNISECI::AlpiMeridionali as i32 => {
Ok(IdroEcoRegioneNISECI::AlpiMeridionali)
}
x if x == IdroEcoRegioneNISECI::Monferrato as i32 => {
Ok(IdroEcoRegioneNISECI::Monferrato)
}
x if x == IdroEcoRegioneNISECI::PianuraPadana as i32 => {
Ok(IdroEcoRegioneNISECI::PianuraPadana)
}
x if x == IdroEcoRegioneNISECI::Carso as i32 => Ok(IdroEcoRegioneNISECI::Carso),
x if x == IdroEcoRegioneNISECI::AppenninoPiemontese as i32 => {
Ok(IdroEcoRegioneNISECI::AppenninoPiemontese)
}
x if x == IdroEcoRegioneNISECI::AlpiMediterranee as i32 => {
Ok(IdroEcoRegioneNISECI::AlpiMediterranee)
}
x if x == IdroEcoRegioneNISECI::AppenninoSettentrionale as i32 => {
Ok(IdroEcoRegioneNISECI::AppenninoSettentrionale)
}
x if x == IdroEcoRegioneNISECI::Toscana as i32 => Ok(IdroEcoRegioneNISECI::Toscana),
x if x == IdroEcoRegioneNISECI::CostaAdriatica as i32 => {
Ok(IdroEcoRegioneNISECI::CostaAdriatica)
}
x if x == IdroEcoRegioneNISECI::AppenninoCentrale as i32 => {
Ok(IdroEcoRegioneNISECI::AppenninoCentrale)
}
x if x == IdroEcoRegioneNISECI::RomaViterbese as i32 => {
Ok(IdroEcoRegioneNISECI::RomaViterbese)
}
x if x == IdroEcoRegioneNISECI::BassoLazio as i32 => {
Ok(IdroEcoRegioneNISECI::BassoLazio)
}
x if x == IdroEcoRegioneNISECI::Vesuvio as i32 => Ok(IdroEcoRegioneNISECI::Vesuvio),
x if x == IdroEcoRegioneNISECI::BasilicataTavoliere as i32 => {
Ok(IdroEcoRegioneNISECI::BasilicataTavoliere)
}
x if x == IdroEcoRegioneNISECI::PugliaCarsica as i32 => {
Ok(IdroEcoRegioneNISECI::PugliaCarsica)
}
x if x == IdroEcoRegioneNISECI::AppenninoMeridionale as i32 => {
Ok(IdroEcoRegioneNISECI::AppenninoMeridionale)
}
x if x == IdroEcoRegioneNISECI::Sicilia as i32 => Ok(IdroEcoRegioneNISECI::Sicilia),
x if x == IdroEcoRegioneNISECI::Sardegna as i32 => Ok(IdroEcoRegioneNISECI::Sardegna),
_ => Err(()),
}
}
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ValoriIntermediSpecieNISECI {
#[deprecated(note = "v0.2 will change visibility.\nConsider using self.densita_stimata()")]
pub densita_stimata: f32,
#[deprecated(note = "v0.2 will change visibility.\nConsider using self.quantita_stimata()")]
pub quantita_stimata: u32,
#[deprecated(note = "v0.2 will change visibility.\nConsider using self.classi_eta()")]
pub classi_eta: ClassiEtaSpecieNISECI,
#[deprecated(note = "v0.2 will change visibility.\nConsider using self.rapporto_ad_juv()")]
pub rapporto_ad_juv: Option<f32>,
#[deprecated(note = "v0.2 will change visibility.\nConsider using self.x2_a_a()")]
pub x2_a_a: u8,
#[deprecated(note = "v0.2 will change visibility.\nConsider using self.x2_a_b()")]
pub x2_a_b: u8,
#[deprecated(note = "v0.2 will change visibility.\nConsider using self.x2_b()")]
pub x2_b: f32,
}
impl fmt::Display for ValoriIntermediSpecieNISECI {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let rapporto_ad_juv_str = match self.rapporto_ad_juv() {
Some(v) => {
format!("{v}")
}
None => "NC".to_string(),
};
let string_representation = format!(
"{}; {}; {}; {}; {}; {}; {}",
self.classi_eta(),
self.densita_stimata(),
self.quantita_stimata(),
self.x2_b(),
rapporto_ad_juv_str,
self.x2_a_a(),
self.x2_a_b()
);
write!(f, "{}", string_representation)
}
}
impl ValoriIntermediSpecieNISECI {
#[inline(always)]
pub fn densita_stimata(&self) -> f32 {
#[expect(deprecated)]
self.densita_stimata
}
#[inline(always)]
pub fn quantita_stimata(&self) -> u32 {
#[expect(deprecated)]
self.quantita_stimata
}
#[inline(always)]
pub(crate) fn classi_eta(&self) -> &ClassiEtaSpecieNISECI {
#[expect(deprecated)]
&self.classi_eta
}
#[inline(always)]
pub(crate) fn rapporto_ad_juv(&self) -> Option<f32> {
#[expect(deprecated)]
self.rapporto_ad_juv
}
#[inline(always)]
pub fn x2_a_a(&self) -> u8 {
#[expect(deprecated)]
self.x2_a_a
}
#[inline(always)]
pub fn x2_a_b(&self) -> u8 {
#[expect(deprecated)]
self.x2_a_b
}
#[inline(always)]
pub fn x2_b(&self) -> f32 {
#[expect(deprecated)]
self.x2_b
}
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ValoriIntermediNISECI {
#[deprecated(note = "v0.2 will change visibility.\nConsider using self.x1()")]
pub x1: f32,
#[deprecated(note = "v0.2 will change visibility.\nConsider using self.x2()")]
pub x2: Option<f32>,
#[deprecated(note = "v0.2 will change visibility.\nConsider using self.x3()")]
pub x3: f32,
#[deprecated(note = "v0.2 will change visibility.\nConsider using self.specie_specifici()")]
pub specie_specifici: HashMap<String, ValoriIntermediSpecieNISECI>,
#[deprecated(note = "v0.2 will change visibility.\nConsider using self.x2_a()")]
pub x2_a: f32,
#[deprecated(note = "v0.2 will change visibility.\nConsider using self.x2_b()")]
pub x2_b: f32,
#[deprecated(note = "v0.2 will change visibility.\nConsider using self.x3_a()")]
pub x3_a: Option<f32>,
#[deprecated(note = "v0.2 will change visibility.\nConsider using self.x3_b()")]
pub x3_b: Option<f32>,
}
impl fmt::Display for ValoriIntermediNISECI {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let x2_str = match self.x2() {
Some(v) => format!("{v}"),
None => "NC".to_string(),
};
let x3_a_str = match self.x3_a() {
Some(v) => format!("{v}"),
None => "NC".to_string(),
};
let x3_b_str = match self.x3_b() {
Some(v) => format!("{v}"),
None => "NC".to_string(),
};
let mut string_representation = format!("x1: {}, x2: {}, x3: {},\nx2_a: {}, x2_b: {}, x3_a: {}, x3_b: {},\n\nspecie, nome latino, tipo autoctono, tipo alloctono, specie attesa, cl1, cl2, cl3, cl4, cl5, densita stimata, quantita stimata, x2_b, rapporto ad/juv, x2a_a, x2a_b\n",
self.x1(), x2_str, self.x3(),
self.x2_a(), self.x2_b(), x3_a_str, x3_b_str);
for (_k, v) in self.specie_specifici().iter() {
string_representation = format!("{}\n{}", string_representation, v);
}
write!(f, "{}", string_representation)
}
}
impl ValoriIntermediNISECI {
#[inline(always)]
pub(crate) fn x1(&self) -> f32 {
#[expect(deprecated)]
self.x1
}
#[inline(always)]
pub(crate) fn x2(&self) -> Option<f32> {
#[expect(deprecated)]
self.x2
}
#[inline(always)]
pub(crate) fn x3(&self) -> f32 {
#[expect(deprecated)]
self.x3
}
#[inline(always)]
pub(crate) fn x2_a(&self) -> f32 {
#[expect(deprecated)]
self.x2_a
}
#[inline(always)]
pub(crate) fn x2_b(&self) -> f32 {
#[expect(deprecated)]
self.x2_b
}
#[inline(always)]
pub(crate) fn x3_a(&self) -> Option<f32> {
#[expect(deprecated)]
self.x3_a
}
#[inline(always)]
pub(crate) fn x3_b(&self) -> Option<f32> {
#[expect(deprecated)]
self.x3_b
}
#[inline(always)]
pub(crate) fn specie_specifici(&self) -> &HashMap<String, ValoriIntermediSpecieNISECI> {
#[expect(deprecated)]
&self.specie_specifici
}
#[deprecated(note = "v0.2 will drop visibility")]
pub fn log(&self) {
println!("Valori intermedi: {{{self}}}");
}
#[deprecated(note = "v0.2 will drop visibility. Consider using self.to_csv_joined() instead")]
pub fn to_csv(&self, comma_csv_delimiter: bool) -> String {
let mut string_representation = if comma_csv_delimiter {
"specie, nome latino, tipo autoctono, tipo alloctono, specie attesa, cl1, cl2, cl3, cl4, cl5, densita stimata, quantita stimata, x2b, rapporto ad/juv, x2a_a, x2a_b".to_string()
} else {
"specie; nome latino; tipo autoctono; tipo alloctono; specie attesa; cl1; cl2; cl3; cl4; cl5; densita stimata; quantita stimata; x2b; rapporto ad/juv; x2a_a; x2a_b".to_string()
};
for (key_id, v) in self.specie_specifici().iter() {
let rapporto_ad_juv_str = match v.rapporto_ad_juv() {
Some(v) => {
if comma_csv_delimiter {
format!("{v}")
} else {
v.comma().to_string()
}
}
None => "NC".to_string(),
};
let specie_attesa_str = if v.classi_eta().specie_attesa() {
"SI"
} else {
"NO"
};
string_representation = if comma_csv_delimiter {
format!(
"{}\n{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}",
string_representation,
key_id,
v.classi_eta().nome(),
v.classi_eta().tipo_autoctono(),
v.classi_eta().tipo_alloctono(),
specie_attesa_str,
v.classi_eta().cl_1(),
v.classi_eta().cl_2(),
v.classi_eta().cl_3(),
v.classi_eta().cl_4(),
v.classi_eta().cl_5(),
v.densita_stimata(),
v.quantita_stimata(),
v.x2_b(),
rapporto_ad_juv_str,
v.x2_a_a(),
v.x2_a_b()
)
} else {
format!(
"{}\n{}; {}; {}; {}; {}; {}; {}; {}; {}; {}; {}; {}; {}; {}; {}; {}",
string_representation,
key_id,
v.classi_eta().nome(),
v.classi_eta().tipo_autoctono(),
v.classi_eta().tipo_alloctono(),
specie_attesa_str,
v.classi_eta().cl_1(),
v.classi_eta().cl_2(),
v.classi_eta().cl_3(),
v.classi_eta().cl_4(),
v.classi_eta().cl_5(),
v.densita_stimata().comma(),
v.quantita_stimata(),
v.x2_b(),
rapporto_ad_juv_str,
v.x2_a_a(),
v.x2_a_b()
)
}
}
string_representation
}
pub fn to_csv_joined(
&self,
riferimento: &RiferimentoNISECI,
comma_csv_delimiter: bool,
) -> String {
let mut string_representation = if comma_csv_delimiter {
"specie, nome latino, tipo autoctono, tipo alloctono, specie attesa, cl1, cl2, cl3, cl4, cl5, densita stimata, quantita stimata, x2b, rapporto ad/juv, x2a_a, x2a_b".to_string()
} else {
"specie; nome latino; tipo autoctono; tipo alloctono; specie attesa; cl1; cl2; cl3; cl4; cl5; densita stimata; quantita stimata; x2b; rapporto ad/juv; x2a_a; x2a_b".to_string()
};
for (key_id, v) in self.specie_specifici().iter() {
let specie_ref = match riferimento.get_ref_by_id(key_id) {
Some(s) => s,
None => {
string_representation = format!(
"{}\n?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?",
string_representation
);
return string_representation;
}
};
let rapporto_ad_juv_str = match v.rapporto_ad_juv() {
Some(v) => {
if comma_csv_delimiter {
format!("{v}")
} else {
v.comma().to_string()
}
}
None => "NC".to_string(),
};
let specie_attesa_str = if specie_ref.specie_attesa() {
"SI"
} else {
"NO"
};
string_representation = if comma_csv_delimiter {
format!(
"{}\n{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}",
string_representation,
key_id,
specie_ref.nome(),
specie_ref.tipo_autoctono(),
specie_ref.tipo_alloctono(),
specie_attesa_str,
v.classi_eta().cl_1(),
v.classi_eta().cl_2(),
v.classi_eta().cl_3(),
v.classi_eta().cl_4(),
v.classi_eta().cl_5(),
v.densita_stimata(),
v.quantita_stimata(),
v.x2_b(),
rapporto_ad_juv_str,
v.x2_a_a(),
v.x2_a_b()
)
} else {
format!(
"{}\n{}; {}; {}; {}; {}; {}; {}; {}; {}; {}; {}; {}; {}; {}; {}; {}",
string_representation,
key_id,
specie_ref.nome(),
specie_ref.tipo_autoctono(),
specie_ref.tipo_alloctono(),
specie_attesa_str,
v.classi_eta().cl_1(),
v.classi_eta().cl_2(),
v.classi_eta().cl_3(),
v.classi_eta().cl_4(),
v.classi_eta().cl_5(),
v.densita_stimata().comma(),
v.quantita_stimata(),
v.x2_b(),
rapporto_ad_juv_str,
v.x2_a_a(),
v.x2_a_b()
)
}
}
string_representation
}
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RisultatoNISECI {
valore: Option<f32>,
rqe: Option<f32>,
valori_intermedi: ValoriIntermediNISECI,
}
impl fmt::Display for RisultatoNISECI {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let valore_str = match self.valore {
Some(v) => format!("{v}"),
None => "NC".to_string(),
};
let rqe_str = match self.rqe {
Some(v) => format!("{v}"),
None => "NC".to_string(),
};
let string_representation = format!("RisultatoNISECI: {{ valore NISECI: {{{}}}, valore RQE NISECI: {{{}}}, valori intermedi: {{{}}} }}", valore_str, rqe_str, self.valori_intermedi);
write!(f, "{}", string_representation)
}
}
impl RisultatoNISECI {
pub fn new(
valore: Option<f32>,
rqe: Option<f32>,
valori_intermedi: ValoriIntermediNISECI,
) -> Self {
Self {
valore,
rqe,
valori_intermedi,
}
}
pub fn get_valore(&self) -> Option<f32> {
self.valore
}
pub fn get_rqe(&self) -> Option<f32> {
self.rqe
}
pub fn get_x1(&self) -> f32 {
self.valori_intermedi.x1()
}
pub fn get_x2(&self) -> Option<f32> {
self.valori_intermedi.x2()
}
pub fn get_x3(&self) -> f32 {
self.valori_intermedi.x3()
}
pub fn get_x3_a(&self) -> Option<f32> {
self.valori_intermedi.x3_a()
}
pub fn get_x3_b(&self) -> Option<f32> {
self.valori_intermedi.x3_b()
}
pub fn to_csv(&self, anagrafica: &AnagraficaNISECI, comma_csv_delimiter: bool) -> String {
let niseci = self.get_valore();
let niseci_str = match niseci {
Some(val) => {
if comma_csv_delimiter {
format!("{val}")
} else {
val.comma().to_string()
}
}
None => "NC".to_string(),
};
let rqe_niseci = self.get_rqe();
let rqe_niseci_str = match rqe_niseci {
Some(val) => {
if comma_csv_delimiter {
format!("{val}")
} else {
val.comma().to_string()
}
}
None => "NC".to_string(),
};
let stato_ecologico =
rqe_niseci.map(|val| StatoEcologicoNISECI::from((val, &anagrafica.area)));
let stato_ecologico_str = match stato_ecologico {
Some(val) => {
format!("{val}")
}
None => "NC".to_string(),
};
let string_representation = if comma_csv_delimiter {
format!("Codice stazione, Data, Regione, Idroecoregione, Area pertinenza, Bacino, NISECI, RQE NISECI, Stato ecologico, x1, x2, x3, x3_a, x3_b\n{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}",
anagrafica.codice_stazione,
anagrafica.date_string,
anagrafica.posizione.regione,
anagrafica.idro_eco_regione,
anagrafica.area,
anagrafica.corpo_idrico,
niseci_str,
rqe_niseci_str,
stato_ecologico_str,
self.get_x1(),
match self.get_x2() {
Some(v) => format!("{v}"),
None => "NC".to_string(),
},
self.get_x3(),
match self.get_x3_a() {
Some(v) => format!("{v}"),
None => "NC".to_string(),
},
match self.get_x3_b() {
Some(v) => format!("{v}"),
None => "NC".to_string(),
}
)
} else {
format!("Codice stazione; Data; Regione; Idroecoregione; Area pertinenza; Bacino; NISECI; RQE NISECI; Stato ecologico; x1; x2; x3; x3_a; x3_b\n{}; {}; {}; {}; {}; {}; {}; {}; {}; {}; {}; {}; {}; {}",
anagrafica.codice_stazione,
anagrafica.date_string,
anagrafica.posizione.regione,
anagrafica.idro_eco_regione,
anagrafica.area,
anagrafica.corpo_idrico,
niseci_str,
rqe_niseci_str,
stato_ecologico_str,
self.get_x1().comma(),
match self.get_x2() {
Some(v) => v.comma().to_string(),
None => "NC".to_string(),
},
self.get_x3().comma(),
match self.get_x3_a() {
Some(v) => v.comma().to_string(),
None => "NC".to_string(),
},
match self.get_x3_b() {
Some(v) => v.comma().to_string(),
None => "NC".to_string(),
}
)
};
string_representation
}
}
#[derive(Clone, Copy)]
pub struct MetricheX2aB {
criterio_b: u8,
rapporto_ad_juv: Option<f32>,
}
impl MetricheX2aB {
pub fn new(criterio_b: u8, rapporto_ad_juv: Option<f32>) -> Self {
Self {
criterio_b,
rapporto_ad_juv,
}
}
pub fn get_criterio_b(&self) -> u8 {
self.criterio_b
}
pub fn get_rapporto_ad_juv(&self) -> Option<f32> {
self.rapporto_ad_juv
}
}
#[derive(Clone, Copy)]
pub struct MetricheX2A {
criterio_a: u8,
criteri_x2a_b: MetricheX2aB,
}
impl MetricheX2A {
pub fn new(criterio_a: u8, criteri_x2a_b: MetricheX2aB) -> Self {
Self {
criterio_a,
criteri_x2a_b,
}
}
pub fn get_criterio_a(&self) -> u8 {
self.criterio_a
}
pub fn get_criterio_b(&self) -> u8 {
self.criteri_x2a_b.get_criterio_b()
}
pub fn get_rapporto_ad_juv(&self) -> Option<f32> {
self.criteri_x2a_b.get_rapporto_ad_juv()
}
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ClassiEtaSpecieNISECI {
#[deprecated(
note = "v0.2 will drop visibility. Consider using self.id(), self.nome(), self.ad_juv_soglia_N() instead"
)]
pub specie: SpecieNISECI,
tipo_autoctono: u8,
tipo_alloctono: u8,
specie_attesa: bool,
ad_juv_soglia_1: f32,
ad_juv_soglia_2: f32,
ad_juv_soglia_3: f32,
ad_juv_soglia_4: f32,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.cl_1() instead")]
pub cl1: u32,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.cl_2() instead")]
pub cl2: u32,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.cl_3() instead")]
pub cl3: u32,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.cl_4() instead")]
pub cl4: u32,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.cl_5() instead")]
pub cl5: u32,
}
impl fmt::Display for ClassiEtaSpecieNISECI {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let specie_attesa_str = match self.specie_attesa() {
true => "SI".to_string(),
false => "NO".to_string(),
};
let string_representation = format!(
"{}; {}; {}; {}; {}; {}; {}; {}; {}; {}",
self.id(),
self.nome(),
self.tipo_autoctono(),
self.tipo_alloctono(),
specie_attesa_str,
self.cl_1(),
self.cl_2(),
self.cl_3(),
self.cl_4(),
self.cl_5()
);
write!(f, "{}", string_representation)
}
}
impl Default for ClassiEtaSpecieNISECI {
fn default() -> Self {
#[expect(deprecated)]
Self::new()
}
}
impl ClassiEtaSpecieNISECI {
#[deprecated(
note = "v0.2 will drop visibility. Consider using ClassiEtaSpecieNISECI::new_cl_prevalorizzata instead"
)]
pub fn new() -> ClassiEtaSpecieNISECI {
ClassiEtaSpecieNISECI {
#[expect(deprecated)]
specie: SpecieNISECI::new_dummy_specie(),
tipo_autoctono: 0,
tipo_alloctono: 0,
specie_attesa: true,
ad_juv_soglia_1: 0.1,
ad_juv_soglia_2: 0.2,
ad_juv_soglia_3: 0.3,
ad_juv_soglia_4: 0.4,
#[expect(deprecated)]
cl1: 0,
#[expect(deprecated)]
cl2: 0,
#[expect(deprecated)]
cl3: 0,
#[expect(deprecated)]
cl4: 0,
#[expect(deprecated)]
cl5: 0,
}
}
pub fn new_cl_prevalorizzata(record: &RecordNISECI) -> ClassiEtaSpecieNISECI {
let mut classe = ClassiEtaSpecieNISECI {
#[expect(deprecated)]
specie: record.specie.clone(),
specie_attesa: record.specie_attesa(),
tipo_autoctono: record.tipo_autoctono(),
tipo_alloctono: record.tipo_alloctono(),
ad_juv_soglia_1: record.ad_juv_soglia_1(),
ad_juv_soglia_2: record.ad_juv_soglia_2(),
ad_juv_soglia_3: record.ad_juv_soglia_3(),
ad_juv_soglia_4: record.ad_juv_soglia_4(),
#[expect(deprecated)]
cl1: 0,
#[expect(deprecated)]
cl2: 0,
#[expect(deprecated)]
cl3: 0,
#[expect(deprecated)]
cl4: 0,
#[expect(deprecated)]
cl5: 0,
};
classe.update_classi_eta(record);
classe
}
pub fn update_classi_eta(&mut self, record: &RecordNISECI) {
match ClassiEta::find_classe_eta(record) {
#[expect(deprecated)]
ClassiEta::CL1 => self.cl1 += 1,
#[expect(deprecated)]
ClassiEta::CL2 => self.cl2 += 1,
#[expect(deprecated)]
ClassiEta::CL3 => self.cl3 += 1,
#[expect(deprecated)]
ClassiEta::CL4 => self.cl4 += 1,
#[expect(deprecated)]
ClassiEta::CL5 => self.cl5 += 1,
}
}
#[inline(always)]
pub(crate) fn cl_1(&self) -> u32 {
#[expect(deprecated)]
self.cl1
}
#[inline(always)]
pub(crate) fn cl_2(&self) -> u32 {
#[expect(deprecated)]
self.cl2
}
#[inline(always)]
pub(crate) fn cl_3(&self) -> u32 {
#[expect(deprecated)]
self.cl3
}
#[inline(always)]
pub(crate) fn cl_4(&self) -> u32 {
#[expect(deprecated)]
self.cl4
}
#[inline(always)]
pub(crate) fn cl_5(&self) -> u32 {
#[expect(deprecated)]
self.cl5
}
#[inline(always)]
pub(crate) fn id(&self) -> &str {
#[expect(deprecated)]
&self.specie.id
}
pub fn nome(&self) -> &str {
#[expect(deprecated)]
&self.specie.nome
}
#[inline(always)]
pub fn specie_attesa(&self) -> bool {
self.specie_attesa
}
#[inline(always)]
pub(crate) fn tipo_autoctono(&self) -> u8 {
self.tipo_autoctono
}
#[inline(always)]
pub(crate) fn tipo_alloctono(&self) -> u8 {
self.tipo_alloctono
}
#[inline(always)]
pub fn ad_juv_soglia_1(&self) -> f32 {
self.ad_juv_soglia_1
}
#[inline(always)]
pub fn ad_juv_soglia_2(&self) -> f32 {
self.ad_juv_soglia_2
}
#[inline(always)]
pub fn ad_juv_soglia_3(&self) -> f32 {
self.ad_juv_soglia_3
}
#[inline(always)]
pub fn ad_juv_soglia_4(&self) -> f32 {
self.ad_juv_soglia_4
}
fn get_how_many_classes(&self) -> usize {
#[expect(deprecated)]
[self.cl1, self.cl2, self.cl3, self.cl4, self.cl5]
.into_iter()
.filter(|&value| value > 0)
.count()
}
pub fn get_x2_a_criterio_a(&self) -> u8 {
let count = self.get_how_many_classes();
if count >= 4 {
return 1;
}
if count == 3 {
return 2;
}
3
}
pub fn get_x2_a_criterio_b(&self) -> (u8, Option<f32>) {
#[expect(deprecated)]
if (self.cl2 + self.cl3) == 0 {
return (3, None);
}
#[expect(deprecated)]
let ad_juv = (self.cl4 + self.cl5) as f32 / (self.cl2 + self.cl3) as f32;
if ad_juv < self.ad_juv_soglia_1() {
return (3, Some(ad_juv));
}
if ad_juv <= self.ad_juv_soglia_2() {
return (2, Some(ad_juv));
}
if ad_juv <= self.ad_juv_soglia_3() {
return (1, Some(ad_juv));
}
if ad_juv <= self.ad_juv_soglia_4() {
return (2, Some(ad_juv));
}
(3, Some(ad_juv))
}
pub fn calculate_struttura_popolazione(&self) -> Result<(f32, MetricheX2A), String> {
let criterio_a: u8 = self.get_x2_a_criterio_a();
let (criterio_b, ad_juv): (u8, Option<f32>) = self.get_x2_a_criterio_b();
if criterio_a == 1 && criterio_b == 3 {
return Ok((
0.5,
MetricheX2A::new(criterio_a, MetricheX2aB::new(criterio_b, ad_juv)),
));
}
if criterio_a == 1 {
return Ok((
1.0,
MetricheX2A::new(criterio_a, MetricheX2aB::new(criterio_b, ad_juv)),
));
}
if criterio_a == 2 && criterio_b == 3 {
return Ok((
0.0,
MetricheX2A::new(criterio_a, MetricheX2aB::new(criterio_b, ad_juv)),
));
}
if criterio_a == 2 {
return Ok((
0.5,
MetricheX2A::new(criterio_a, MetricheX2aB::new(criterio_b, ad_juv)),
));
}
if criterio_a == 3 {
return Ok((
0.0,
MetricheX2A::new(criterio_a, MetricheX2aB::new(criterio_b, ad_juv)),
));
}
Err(format!(
"Il Criterio A o B di x2a è diverso da 1 o 2 o 3. criterio A = {}, criterio B = {}",
criterio_a, criterio_b
))
}
}
pub enum ClassiEta {
CL1,
CL2,
CL3,
CL4,
CL5,
}
impl ClassiEta {
pub fn find_classe_eta(record: &RecordNISECI) -> ClassiEta {
if record.lunghezza() < record.cl_soglia_1() {
ClassiEta::CL1
} else if record.lunghezza() < record.cl_soglia_2() {
ClassiEta::CL2
} else if record.lunghezza() < record.cl_soglia_3() {
ClassiEta::CL3
} else if record.lunghezza() < record.cl_soglia_4() {
ClassiEta::CL4
} else {
ClassiEta::CL5
}
}
}
pub struct InfoIntermediePopolazioniNISECI {
criterio_a: u8,
criterio_b: u8,
rapporto_ad_juv: Option<f32>,
}
impl InfoIntermediePopolazioniNISECI {
pub fn new(
criterio_a: u8,
criterio_b: u8,
rapporto_ad_juv: Option<f32>,
) -> InfoIntermediePopolazioniNISECI {
InfoIntermediePopolazioniNISECI {
criterio_a,
criterio_b,
rapporto_ad_juv,
}
}
pub fn get_criterio_a(&self) -> u8 {
self.criterio_a
}
pub fn get_criterio_b(&self) -> u8 {
self.criterio_b
}
pub fn get_rapporto_ad_juv(&self) -> Option<f32> {
self.rapporto_ad_juv
}
}
pub struct InfoPopolazioniNISECI {
#[deprecated(
note = "v0.2 will drop visibility. Consider using self.popolazione_piu_strutt() instead"
)]
pub popolazione_piu_strutt: f32,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.species_strutt() instead")]
pub species_strutt: u32,
#[deprecated(
note = "v0.2 will drop visibility. Consider using self.species_mediamente_strutt() instead"
)]
pub species_mediamente_strutt: u32,
#[deprecated(
note = "v0.2 will drop visibility. Consider using self.species_destrutt() instead"
)]
pub species_destrutt: u32,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.tot_species() instead")]
pub tot_species: usize,
#[deprecated(
note = "v0.2 will drop visibility. Consider using self.intermediates_map() instead"
)]
pub intermediates_map: HashMap<String, InfoIntermediePopolazioniNISECI>,
}
impl Default for InfoPopolazioniNISECI {
fn default() -> Self {
Self::new()
}
}
impl InfoPopolazioniNISECI {
pub fn new() -> InfoPopolazioniNISECI {
InfoPopolazioniNISECI {
#[expect(deprecated)]
popolazione_piu_strutt: 0.0,
#[expect(deprecated)]
species_strutt: 0,
#[expect(deprecated)]
species_mediamente_strutt: 0,
#[expect(deprecated)]
species_destrutt: 0,
#[expect(deprecated)]
tot_species: 0,
#[expect(deprecated)]
intermediates_map: HashMap::new(),
}
}
#[inline(always)]
pub fn popolazione_piu_strutt(&self) -> f32 {
#[expect(deprecated)]
self.popolazione_piu_strutt
}
#[inline(always)]
pub fn species_strutt(&self) -> u32 {
#[expect(deprecated)]
self.species_strutt
}
#[inline(always)]
pub fn species_mediamente_strutt(&self) -> u32 {
#[expect(deprecated)]
self.species_mediamente_strutt
}
#[inline(always)]
pub fn species_destrutt(&self) -> u32 {
#[expect(deprecated)]
self.species_destrutt
}
#[inline(always)]
pub fn tot_species(&self) -> usize {
#[expect(deprecated)]
self.tot_species
}
#[inline(always)]
pub(crate) fn intermediates_map(&self) -> &HashMap<String, InfoIntermediePopolazioniNISECI> {
#[expect(deprecated)]
&self.intermediates_map
}
pub fn get_info_pop(
map: &HashMap<String, ClassiEtaSpecieNISECI>,
) -> Result<InfoPopolazioniNISECI, Vec<String>> {
let mut errors: Vec<String> = Vec::with_capacity(map.len());
let mut info_pop = InfoPopolazioniNISECI::new();
#[expect(deprecated)]
{
info_pop.tot_species = map.len();
}
let epsilon: f32 = 1e-6;
for classe in map.values() {
match classe.calculate_struttura_popolazione() {
Ok((popolazione, criteri_x2_a)) => {
if info_pop.popolazione_piu_strutt() < popolazione {
#[expect(deprecated)]
{
info_pop.popolazione_piu_strutt = popolazione;
}
}
if (popolazione - 1.0).abs() < epsilon {
#[expect(deprecated)]
{
info_pop.species_strutt += 1;
}
}
if (popolazione - 0.5).abs() < epsilon {
#[expect(deprecated)]
{
info_pop.species_mediamente_strutt += 1;
}
}
if popolazione.abs() < epsilon {
#[expect(deprecated)]
{
info_pop.species_destrutt += 1;
}
}
let criterio_a = criteri_x2_a.get_criterio_a();
let criterio_b = criteri_x2_a.get_criterio_b();
let rapporto_ad_juv = criteri_x2_a.get_rapporto_ad_juv();
#[expect(deprecated)]
info_pop.intermediates_map.insert(
classe.id().to_string(),
InfoIntermediePopolazioniNISECI::new(
criterio_a,
criterio_b,
rapporto_ad_juv,
),
);
}
Err(error) => errors.push(error),
}
}
if !errors.is_empty() {
errors.shrink_to_fit();
return Err(errors);
}
Ok(info_pop)
}
}
pub struct InfoPopolazioniAlieneNISECI {
#[deprecated(note = "v0.2 will drop visibility. Consider using self.tipo_1() instead")]
pub tipo_1: InfoPopolazioniNISECI,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.tipo_2() instead")]
pub tipo_2: InfoPopolazioniNISECI,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.tipo_3() instead")]
pub tipo_3: InfoPopolazioniNISECI,
#[deprecated(
note = "v0.2 will drop visibility. Consider using self.tot_specie_aliene() instead"
)]
pub tot_specie_aliene: usize,
#[deprecated(
note = "v0.2 will drop visibility. Consider using self.tot_specie_autoctone() instead"
)]
pub tot_specie_autoctone: usize,
}
impl InfoPopolazioniAlieneNISECI {
#[cfg(test)]
pub fn new() -> InfoPopolazioniAlieneNISECI {
InfoPopolazioniAlieneNISECI {
#[expect(deprecated)]
tipo_1: InfoPopolazioniNISECI::new(),
#[expect(deprecated)]
tipo_2: InfoPopolazioniNISECI::new(),
#[expect(deprecated)]
tipo_3: InfoPopolazioniNISECI::new(),
#[expect(deprecated)]
tot_specie_aliene: 0,
#[expect(deprecated)]
tot_specie_autoctone: 0,
}
}
#[inline(always)]
pub(crate) fn tipo_1(&self) -> &InfoPopolazioniNISECI {
#[expect(deprecated)]
&self.tipo_1
}
#[inline(always)]
pub(crate) fn tipo_2(&self) -> &InfoPopolazioniNISECI {
#[expect(deprecated)]
&self.tipo_2
}
#[inline(always)]
pub(crate) fn tipo_3(&self) -> &InfoPopolazioniNISECI {
#[expect(deprecated)]
&self.tipo_3
}
#[inline(always)]
pub(crate) fn tot_specie_aliene(&self) -> usize {
#[expect(deprecated)]
self.tot_specie_aliene
}
#[inline(always)]
pub(crate) fn tot_specie_autoctone(&self) -> usize {
#[expect(deprecated)]
self.tot_specie_autoctone
}
pub fn get_info_pop_aliene(
classi_eta: &ClassiEtaAlieniNISECI,
) -> Result<InfoPopolazioniAlieneNISECI, Vec<String>> {
#[expect(deprecated)]
let tipo_1 = InfoPopolazioniNISECI::get_info_pop(&classi_eta.map_tipo_1)?;
#[expect(deprecated)]
let tipo_2 = InfoPopolazioniNISECI::get_info_pop(&classi_eta.map_tipo_2)?;
#[expect(deprecated)]
let tipo_3 = InfoPopolazioniNISECI::get_info_pop(&classi_eta.map_tipo_3)?;
let info_pop_aliene = InfoPopolazioniAlieneNISECI {
#[expect(deprecated)]
tipo_1,
#[expect(deprecated)]
tipo_2,
#[expect(deprecated)]
tipo_3,
#[expect(deprecated)]
tot_specie_aliene: classi_eta.tot_specie_aliene,
#[expect(deprecated)]
tot_specie_autoctone: classi_eta.tot_specie_autoctone,
};
Ok(info_pop_aliene)
}
pub fn get_species_mediamente_strutt(&self) -> u32 {
#[expect(deprecated)]
{
self.tipo_1.species_mediamente_strutt()
+ self.tipo_2.species_mediamente_strutt()
+ self.tipo_3.species_mediamente_strutt()
}
}
pub fn get_species_destrutt(&self) -> u32 {
#[expect(deprecated)]
{
self.tipo_1.species_destrutt()
+ self.tipo_2.species_destrutt()
+ self.tipo_3.species_destrutt()
}
}
}
pub struct ClassiEtaAlieniNISECI {
#[deprecated(note = "v0.2 will drop visibility.")]
pub map_tipo_1: HashMap<String, ClassiEtaSpecieNISECI>,
#[deprecated(note = "v0.2 will drop visibility.")]
pub map_tipo_2: HashMap<String, ClassiEtaSpecieNISECI>,
#[deprecated(note = "v0.2 will drop visibility.")]
pub map_tipo_3: HashMap<String, ClassiEtaSpecieNISECI>,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.tot_specie_aliene()")]
pub tot_specie_aliene: usize,
#[deprecated(note = "v0.2 will drop visibility. Consider using self.tot_specie_autoctone()")]
pub tot_specie_autoctone: usize,
}
impl Default for ClassiEtaAlieniNISECI {
fn default() -> Self {
Self::new()
}
}
impl ClassiEtaAlieniNISECI {
pub fn new() -> ClassiEtaAlieniNISECI {
ClassiEtaAlieniNISECI {
#[expect(deprecated)]
map_tipo_1: HashMap::with_capacity(10),
#[expect(deprecated)]
map_tipo_2: HashMap::with_capacity(10),
#[expect(deprecated)]
map_tipo_3: HashMap::with_capacity(10),
#[expect(deprecated)]
tot_specie_aliene: 0,
#[expect(deprecated)]
tot_specie_autoctone: 0,
}
}
pub fn tot_specie_aliene(&self) -> usize {
#[expect(deprecated)]
self.tot_specie_aliene
}
pub fn tot_specie_autoctone(&self) -> usize {
#[expect(deprecated)]
self.tot_specie_autoctone
}
}
pub struct EsemplariPerCattura {
#[deprecated(note = "v0.2 will drop visibility")]
pub specie: SpecieNISECI,
#[deprecated(note = "v0.2 will drop visibility")]
pub mappa: HashMap<u8, u32>, dens_soglia_1: f32,
dens_soglia_2: f32,
}
impl EsemplariPerCattura {
#[inline(always)]
pub(crate) fn id(&self) -> &str {
#[expect(deprecated)]
self.specie.id()
}
#[inline(always)]
pub(crate) fn dens_soglia_1(&self) -> f32 {
self.dens_soglia_1
}
#[inline(always)]
pub(crate) fn dens_soglia_2(&self) -> f32 {
self.dens_soglia_2
}
pub(crate) fn new(specie: &SpecieNISECI) -> Self {
EsemplariPerCattura {
#[expect(deprecated)]
specie: specie.clone(),
#[expect(deprecated)]
mappa: HashMap::new(),
dens_soglia_1: specie.dens_soglia_1(),
dens_soglia_2: specie.dens_soglia_2(),
}
}
#[deprecated(
note = "v0.2 will drop visibility. Consider using EsemplariPerCattura::new().fill_passaggio() instead"
)]
pub fn new_prevalorized(numero_passaggio: u8, specie: &SpecieNISECI) -> EsemplariPerCattura {
let mut mappa: HashMap<u8, u32> = HashMap::new();
mappa.insert(numero_passaggio, 1);
EsemplariPerCattura {
#[expect(deprecated)]
specie: specie.clone(),
#[expect(deprecated)]
mappa,
dens_soglia_1: specie.dens_soglia_1(),
dens_soglia_2: specie.dens_soglia_2(),
}
}
pub fn fill_passaggio(&mut self, numero_passaggio: u8) {
#[expect(deprecated)]
match self.mappa.entry(numero_passaggio) {
Entry::Occupied(occupied) => {
let numero_esemplari = occupied.get() + 1;
self.mappa.insert(numero_passaggio, numero_esemplari);
}
Entry::Vacant(_) => {
self.mappa.insert(numero_passaggio, 1);
}
}
}
}
pub enum StatoEcologicoNISECI {
Elevato,
Buono,
Moderato,
Scadente,
Cattivo,
}
impl fmt::Display for StatoEcologicoNISECI {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let string_representation = match *self {
StatoEcologicoNISECI::Elevato => "Elevato",
StatoEcologicoNISECI::Buono => "Buono",
StatoEcologicoNISECI::Moderato => "Moderato",
StatoEcologicoNISECI::Scadente => "Scadente",
StatoEcologicoNISECI::Cattivo => "Cattivo",
};
write!(f, "{}", string_representation)
}
}
const STATO_ECOLOGICO_NISECI_SOGLIA_ELEVATO: f32 = 0.8;
const STATO_ECOLOGICO_NISECI_SOGLIA_BUONO_AREA_ALPINA: f32 = 0.52;
const STATO_ECOLOGICO_NISECI_SOGLIA_BUONO_AREA_MEDITERRANEA: f32 = 0.6;
const STATO_ECOLOGICO_NISECI_SOGLIA_MODERATO: f32 = 0.4;
const STATO_ECOLOGICO_NISECI_SOGLIA_SCADENTE: f32 = 0.2;
impl From<(f32, &AreaNISECI)> for StatoEcologicoNISECI {
fn from((val, area): (f32, &AreaNISECI)) -> Self {
if val >= STATO_ECOLOGICO_NISECI_SOGLIA_ELEVATO {
return StatoEcologicoNISECI::Elevato;
}
match area {
AreaNISECI::Alpina => {
if val >= STATO_ECOLOGICO_NISECI_SOGLIA_BUONO_AREA_ALPINA {
return StatoEcologicoNISECI::Buono;
}
}
AreaNISECI::Mediterranea => {
if val >= STATO_ECOLOGICO_NISECI_SOGLIA_BUONO_AREA_MEDITERRANEA {
return StatoEcologicoNISECI::Buono;
}
}
}
if val >= STATO_ECOLOGICO_NISECI_SOGLIA_MODERATO {
return StatoEcologicoNISECI::Moderato;
}
if val >= STATO_ECOLOGICO_NISECI_SOGLIA_SCADENTE {
return StatoEcologicoNISECI::Scadente;
}
StatoEcologicoNISECI::Cattivo
}
}
#[cfg(test)]
mod domain_niseci_private_tests {
use super::*;
#[cfg(feature = "lessclone")]
#[cfg(test)]
impl RiferimentoNISECI {
#[cfg(feature = "lessclone")]
#[cfg(test)]
pub(crate) fn push(&mut self, value: SpecieNISECI) -> IdSpecieNISECI {
eprintln!("Pushing specie {} in riferimento", value.id());
if !self.contains_id(value.id()) {
eprintln!(
"Specie id {} nome {} was NOT in riferimento already",
value.id(),
value.nome()
);
self.map_ids.intern(value.id(), value.clone())
} else {
let inner_id = self
.get_inner_id(value.id())
.expect("contains_id was checked");
eprintln!(
"Specie id {} nome {} was in riferimento already with id",
inner_id,
value.nome()
);
inner_id
}
}
}
#[cfg(not(feature = "lessclone"))]
#[cfg(test)]
impl CampionamentoNISECI {
#[cfg(not(feature = "lessclone"))]
#[cfg(test)]
pub(crate) fn push(&mut self, value: RecordNISECI) {
#[allow(deprecated)]
self.campionamento.push(value);
}
#[cfg(not(feature = "lessclone"))]
#[cfg(test)]
pub(crate) fn as_mut_vec(&mut self) -> &mut Vec<RecordNISECI> {
#[allow(deprecated)]
&mut self.campionamento
}
}
#[cfg(test)]
impl ClassiEtaSpecieNISECI {
#[cfg(test)]
pub(crate) fn new_custom(
specie: &SpecieNISECI,
cl1: u32,
cl2: u32,
cl3: u32,
cl4: u32,
cl5: u32,
) -> Self {
Self {
#[expect(deprecated)]
specie: specie.clone(),
tipo_autoctono: specie.tipo_autoctono(),
tipo_alloctono: specie.tipo_alloctono(),
specie_attesa: specie.specie_attesa(),
ad_juv_soglia_1: specie.ad_juv_soglia_1(),
ad_juv_soglia_2: specie.ad_juv_soglia_2(),
ad_juv_soglia_3: specie.ad_juv_soglia_3(),
ad_juv_soglia_4: specie.ad_juv_soglia_4(),
#[expect(deprecated)]
cl1,
#[expect(deprecated)]
cl2,
#[expect(deprecated)]
cl3,
#[expect(deprecated)]
cl4,
#[expect(deprecated)]
cl5,
}
}
}
#[cfg(test)]
impl AnagraficaNISECI {
#[cfg(test)]
pub(crate) fn new_raw_unchecked(
comunita: ComunitaNISECI,
codice_stazione: String,
date_string: String,
area: AreaNISECI,
corpo_idrico: String,
bacino_appartenenza: String,
idro_eco_regione: IdroEcoRegioneNISECI,
posizione: Location,
lunghezza_media_stazione: f32,
larghezza_media_stazione: f32,
) -> Self {
Self {
comunita,
codice_stazione,
date_string,
area,
corpo_idrico,
bacino_appartenenza,
idro_eco_regione,
posizione,
#[allow(deprecated)]
lunghezza_media_stazione,
#[allow(deprecated)]
larghezza_media_stazione,
}
}
#[cfg(test)]
pub(crate) fn set_lunghezza_unchecked(&mut self, val: f32) {
#[allow(deprecated)]
{
self.lunghezza_media_stazione = val;
}
}
#[cfg(test)]
pub(crate) fn set_larghezza_unchecked(&mut self, val: f32) {
#[allow(deprecated)]
{
self.larghezza_media_stazione = val;
}
}
}
}