use std::num::NonZeroUsize;
use std::sync::Arc;
use rayon::prelude::*;
use stem_material::prelude::*;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use super::wire::Wire;
use crate::error::Error;
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct WireGroup {
pub wire: Box<dyn Wire>,
pub number_wires: NonZeroUsize,
}
impl WireGroup {
pub fn new(wire: Box<dyn Wire>, number_wires: NonZeroUsize) -> Self {
return Self { wire, number_wires };
}
}
impl Clone for WireGroup {
fn clone(&self) -> Self {
Self {
wire: dyn_clone::clone_box(&*self.wire),
number_wires: self.number_wires.clone(),
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct StrandedWire(Vec<WireGroup>);
impl StrandedWire {
pub fn new(wire_groups: Vec<WireGroup>) -> Result<Self, Error> {
return StrandedWire(wire_groups).check();
}
fn check(self) -> Result<Self, Error> {
if let Some(first_wire) = self.0.first() {
for wire_group in self.0.iter().skip(1) {
if first_wire.wire.material() != wire_group.wire.material() {
return Err(Error::InequalMaterials);
}
}
} else {
return Err(Error::EmptyStrandList);
}
return Ok(self);
}
}
#[cfg_attr(feature = "serde", typetag::serde)]
impl Wire for StrandedWire {
fn material(&self) -> &Material {
return unsafe { self.0.get_unchecked(0) }.wire.material();
}
fn material_arc(&self) -> Arc<Material> {
return unsafe { self.0.get_unchecked(0) }.wire.material_arc();
}
fn effective_conductor_area(&self, zone_area: Area, turns: usize) -> Area {
return self
.0
.as_slice()
.par_iter()
.map(|strand| {
return strand.wire.effective_conductor_area(zone_area, turns)
* (usize::from(strand.number_wires) as f64);
})
.sum();
}
fn effective_overall_area(&self, zone_area: Area, turns: usize) -> Area {
return self
.0
.as_slice()
.par_iter()
.map(|strand| {
return strand.wire.effective_overall_area(zone_area, turns)
* (usize::from(strand.number_wires) as f64);
})
.sum();
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for StrandedWire {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(Deserialize)]
struct StrandedWireSerde(Vec<WireGroup>);
let wire_serde = StrandedWireSerde::deserialize(deserializer)?;
return StrandedWire(wire_serde.0)
.check()
.map_err(serde::de::Error::custom);
}
}