Skip to content

Commit

Permalink
Add iterator functionalities to SIArray1 (#48)
Browse files Browse the repository at this point in the history
* Add iterator functionalities to SIArray1

* make implementation more generic

* fix anomalous capitalization

* Update files for release
  • Loading branch information
prehner authored Jun 8, 2022
1 parent d684917 commit 3bca25e
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 4 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.5.1] - 2022-06-08
### Added
- Added implementations of `IntoIterator` for every `Quantity` with iteratable inner types. [#48](https://github.com/itt-ustutt/quantity/pull/48)
- Implemented `FromIterator` for `QuantityArray1`, enabling the use of `collect()` for quantity arrays. [#48](https://github.com/itt-ustutt/quantity/pull/48)

## [0.5.0] - 2022-03-09
### Packaging
- Updated `pyo3` and `numpy` dependencies to 0.16.
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "quantity"
version = "0.5.0"
version = "0.5.1"
authors = ["Philipp Rehner <[email protected]>",
"Gernot Bauer <[email protected]>"]
edition = "2018"
Expand Down
2 changes: 1 addition & 1 deletion si-units/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "si-units"
version = "0.5.0"
version = "0.5.1"
authors = ["Philipp Rehner <[email protected]>",
"Gernot Bauer <[email protected]>"]
edition = "2018"
Expand Down
118 changes: 118 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ use ndarray::*;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::fmt;
use std::iter::FromIterator;
use std::ops::{
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
};
Expand Down Expand Up @@ -1089,3 +1090,120 @@ impl<U: Unit> QuantityArray1<U> {
Self::from_shape_fn(vec.len(), |i| vec[i])
}
}

pub struct QuantityIter<I, U> {
inner: I,
unit: U,
}

impl<'a, I: Iterator<Item = &'a f64>, U: Copy> Iterator for QuantityIter<I, U> {
type Item = QuantityScalar<U>;

fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|value| QuantityScalar {
value: *value,
unit: self.unit,
})
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}

impl<'a, I: Iterator<Item = &'a f64> + ExactSizeIterator, U: Copy> ExactSizeIterator
for QuantityIter<I, U>
{
fn len(&self) -> usize {
self.inner.len()
}
}

impl<'a, I: Iterator<Item = &'a f64> + DoubleEndedIterator, U: Copy> DoubleEndedIterator
for QuantityIter<I, U>
{
fn next_back(&mut self) -> Option<Self::Item> {
self.inner.next_back().map(|value| QuantityScalar {
value: *value,
unit: self.unit,
})
}
}

impl<'a, F, U: Copy> IntoIterator for &'a Quantity<F, U>
where
&'a F: IntoIterator<Item = &'a f64>,
{
type Item = QuantityScalar<U>;
type IntoIter = QuantityIter<<&'a F as IntoIterator>::IntoIter, U>;

fn into_iter(self) -> Self::IntoIter {
QuantityIter {
inner: (&self.value).into_iter(),
unit: self.unit,
}
}
}

impl<U: Unit> FromIterator<QuantityScalar<U>> for QuantityArray1<U> {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = QuantityScalar<U>>,
{
let (value, unit) =
iter.into_iter()
.fold((Vec::new(), U::DIMENSIONLESS), |(mut value, unit), q| {
value.push(q.value);
if unit != q.unit && unit != U::DIMENSIONLESS {
panic!("Inconsistent units {unit} and {}", q.unit);
}
(value, q.unit)
});
let value = Array1::from_vec(value);
Self { value, unit }
}
}

#[cfg(test)]
mod test {
use crate::si::*;
use std::iter::once;

#[test]
fn test_into_iter() {
let x = SIArray1::linspace(1.0 * METER, 3.0 * METER, 6).unwrap();
for q in &x {
println!("{q}");
}
let mut x_iter = x.into_iter();
assert_eq!(x_iter.next(), Some(1.0 * METER));
assert_eq!(x_iter.next(), Some(1.4 * METER));
assert_eq!(x_iter.next(), Some(1.8 * METER));
assert_eq!(x_iter.next(), Some(2.2 * METER));
assert_eq!(x_iter.next(), Some(2.6 * METER));
assert_eq!(x_iter.next(), Some(3.0 * METER));
assert_eq!(x_iter.next(), None);
}

#[test]
fn test_collect_vec() {
let vec: Vec<_> = once(KELVIN).chain(once(METER)).collect();
assert_eq!(vec[0], KELVIN);
assert_eq!(vec[1], METER);
}

#[test]
#[should_panic(expected = "Inconsistent units K and m")]
fn test_collect_array_wrong() {
let arr: SIArray1 = once(KELVIN).chain(once(METER)).collect();
println!("{arr}");
}

#[test]
fn test_collect_array_correct() {
let arr: SIArray1 = once(KELVIN).chain(once(25.0 * CELSIUS)).collect();
println!("{arr}");
assert_eq!(arr.get(0), KELVIN);
assert_eq!(arr.get(1), 25.0 * CELSIUS);
}
}
4 changes: 2 additions & 2 deletions src/si_fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ fn unit_to_latex(symbols: &[&str], exponents: &[i8], prefix: Option<&str>) -> St
let num_st = unit_to_latex_product(num);
let den_st = unit_to_latex_product(den);
match (num_st, den_st) {
(None, None) => format!(""),
(None, None) => String::new(),
(Some(num), None) => format!("\\mathrm{{{}}}", num),
(None, Some(den)) => format!("\\mathrm{{\\frac{{1}}{{{}}}}}", den),
(Some(num), Some(den)) => format!("\\mathrm{{\\frac{{{}}}{{{}}}}}", num, den),
Expand Down Expand Up @@ -282,7 +282,7 @@ fn insert_derived_unit(map: &mut HashMap<SIUnit, SIUnitSymbol>, s: &'static str)
let unit = unit.unwrap();
map.insert(
unit.unit,
(unit, s.replace("*", ""), has_prefix, symbols, exponents),
(unit, s.replace('*', ""), has_prefix, symbols, exponents),
);
}

Expand Down

0 comments on commit 3bca25e

Please sign in to comment.