use crate::constants::MAX_ZOOM;
use serde::Serialize;
use std::num::ParseIntError;
use std::ops::BitAnd;
use crate::errors::UtilesCoreResult;
use crate::UtilesCoreError;
use crate::UtilesCoreError::InvalidZoom;
#[must_use]
pub fn zoom_max_xy(zoom: u8) -> u32 {
2_u32.pow(u32::from(zoom)) - 1
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Serialize)]
pub struct ZoomSet(u32);
#[must_use]
pub fn zset2zvec(zset: u32) -> Vec<u8> {
if zset & (1 << 31) != 0 {
zset2zvec(zset.reverse_bits() >> 1)
} else {
(0u8..31).filter(|&i| (zset & (1u32 << i)) != 0).collect()
}
}
#[must_use]
pub fn zvec2zset(zvec: &[u8]) -> u32 {
zvec.iter().fold(0, |acc, &z| acc | (1 << z))
}
#[must_use]
pub fn zset2zvec_rev(zset: u32) -> Vec<u8> {
zset2zvec(zset.reverse_bits() >> 1)
}
#[must_use]
pub fn zvec2zset_rev(zvec: &[u8]) -> u32 {
zvec.iter().fold(0, |acc, &z| acc | (1 << (31 - z)))
}
impl ZoomSet {
#[must_use]
pub fn new(zset: u32) -> Self {
Self(zset)
}
#[must_use]
pub fn from_zooms(zooms: &[u8]) -> Self {
Self(zvec2zset(zooms))
}
#[must_use]
pub fn to_zooms(&self) -> Vec<u8> {
zset2zvec(self.0)
}
#[must_use]
pub fn all() -> Self {
Self(0b0111_1111_1111_1111_1111_1111_1111_1111)
}
#[must_use]
pub fn zoom_ranges(&self) -> Vec<ZoomRange> {
let mut ranges: Vec<ZoomRange> = vec![];
let mut min: u8 = 0;
let mut max: u8 = 0;
let mut i: u8 = 0;
while i < MAX_ZOOM {
if self.0 & (1 << i) != 0 {
if min == 0 {
min = i;
}
max = i;
} else if min != 0 {
ranges.push(ZoomRange::new(min, max));
min = 0;
max = 0;
}
i += 1;
}
if min != 0 {
ranges.push(ZoomRange::new(min, max));
}
ranges
}
}
impl From<u8> for ZoomSet {
fn from(zoom: u8) -> Self {
ZoomSet(1 << zoom)
}
}
impl From<u32> for ZoomSet {
fn from(zset: u32) -> Self {
ZoomSet(zset)
}
}
impl From<ZoomSet> for Vec<u8> {
fn from(zset: ZoomSet) -> Self {
zset2zvec(zset.0)
}
}
impl TryFrom<Vec<u8>> for ZoomSet {
type Error = UtilesCoreError;
fn try_from(zvec: Vec<u8>) -> Result<Self, Self::Error> {
let result = zvec.iter().try_fold(0u32, |acc, &z| {
if z > MAX_ZOOM {
Err(InvalidZoom(z.to_string()))
} else {
Ok(acc | (1 << z))
}
})?;
Ok(ZoomSet::new(result)) }
}
impl BitAnd for ZoomSet {
type Output = ZoomSet;
fn bitand(self, rhs: Self) -> Self::Output {
ZoomSet(self.0 & rhs.0)
}
}
impl BitAnd<u32> for ZoomSet {
type Output = ZoomSet;
fn bitand(self, rhs: u32) -> Self::Output {
ZoomSet(self.0 & rhs)
}
}
impl BitAnd<ZoomSet> for u32 {
type Output = ZoomSet;
fn bitand(self, rhs: ZoomSet) -> Self::Output {
ZoomSet(self & rhs.0)
}
}
impl BitAnd<u8> for ZoomSet {
type Output = ZoomSet;
fn bitand(self, rhs: u8) -> Self::Output {
ZoomSet(self.0 & (1 << (31 - rhs)))
}
}
type ZoomsSetInt = u32;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ZoomRange {
pub min: u8,
pub max: u8,
}
impl Default for ZoomRange {
fn default() -> Self {
Self {
min: 0,
max: MAX_ZOOM,
}
}
}
impl ZoomRange {
#[must_use]
pub fn new(min: u8, max: u8) -> Self {
Self { min, max }
}
#[must_use]
pub fn from_max(max: u8) -> Self {
Self { min: 0, max }
}
#[must_use]
pub fn from_min(min: u8) -> Self {
Self { min, max: 30 }
}
}
impl IntoIterator for ZoomRange {
type Item = u8;
type IntoIter = std::ops::RangeInclusive<u8>;
fn into_iter(self) -> Self::IntoIter {
self.min..=self.max
}
}
impl From<ZoomRange> for ZoomSet {
fn from(zoom_range: ZoomRange) -> Self {
ZoomSet(zoom_range.into_iter().fold(0, |acc, z| acc | (1 << z)))
}
}
pub fn parse_zooms(zstr: &str) -> UtilesCoreResult<Vec<u8>> {
let mut zvec: Vec<u8> = vec![];
for z in zstr.split(',') {
if z.contains('-') {
let zrange: Result<Vec<u8>, ParseIntError> =
z.split('-').map(str::parse).collect::<Result<Vec<_>, _>>();
let zrange = match zrange {
Ok(zrange) => match zrange.len() {
1 => vec![zrange[0]],
2 => (zrange[0]..=zrange[1]).collect(),
_ => vec![],
},
Err(_) => return Err(InvalidZoom(z.to_string())),
};
zvec.extend(zrange);
} else {
match z.parse::<u8>() {
Ok(num) => zvec.push(num),
Err(_) => return Err(InvalidZoom(z.to_string())),
}
}
}
for z in &zvec {
if *z > 32 {
return Err(InvalidZoom((*z).to_string()));
}
}
zvec.sort_unstable();
zvec.dedup();
Ok(zvec)
}
pub enum ZoomOrZooms {
Zoom(u8),
Zooms(Vec<u8>),
}
impl From<u8> for ZoomOrZooms {
fn from(zoom: u8) -> Self {
ZoomOrZooms::Zoom(zoom)
}
}
impl From<Vec<u8>> for ZoomOrZooms {
fn from(zooms: Vec<u8>) -> Self {
ZoomOrZooms::Zooms(zooms)
}
}
impl From<ZoomOrZooms> for ZoomsSetInt {
fn from(zoom_or_zooms: ZoomOrZooms) -> Self {
match zoom_or_zooms {
ZoomOrZooms::Zoom(zoom) => 1 << (31 - zoom),
ZoomOrZooms::Zooms(zooms) => zvec2zset_rev(&zooms),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zset2zvec_none() {
let zset: u32 = 0b0000_0000_0000_0000_0000_0000_0000_0000;
let zvec: Vec<u8> = vec![];
assert_eq!(zset2zvec(zset), zvec);
assert_eq!(zset2zvec_rev(zset), zvec);
assert_eq!(zset, 0);
}
#[test]
fn zset2zvec_0_1_2() {
let zset_fwd: u32 = 0b0000_0000_0000_0000_0000_0000_0000_0111;
let zset_rev: u32 = 0b1111_0000_0000_0000_0000_0000_0000_0000;
let zvec: Vec<u8> = vec![0, 1, 2];
assert_eq!(zset2zvec(zset_fwd), zvec);
assert_eq!(zset_fwd, 7);
assert_eq!(zset2zvec_rev(zset_rev), zvec);
}
#[test]
fn zset2zvec_all() {
let zset_int_fwd: u32 = 0b0111_1111_1111_1111_1111_1111_1111_1111;
let zset_int_rev: u32 = 0b1111_1111_1111_1111_1111_1111_1111_1111;
let zvec: Vec<u8> = vec![
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
];
assert_eq!(zset2zvec(zset_int_fwd), zvec);
assert_eq!(zset2zvec_rev(zset_int_rev), zvec);
}
#[test]
fn zvec2zset_none() {
let zset_int: u32 = 0b0000_0000_0000_0000_0000_0000_0000_0000;
assert!(zset2zvec(zset_int).is_empty());
assert!(zset2zvec_rev(zset_int).is_empty());
}
#[test]
fn zvec2zset_0_1_2() {
let zset_int: u32 = 0b1110_0000_0000_0000_0000_0000_0000_0000;
let zvec: Vec<u8> = vec![0, 1, 2];
assert_eq!(zvec2zset_rev(&zvec), zset_int);
}
#[test]
fn zvec2zset_0_1_2_3_4_5_6_7() {
let zset_int: u32 = 0b1111_1111_0000_0000_0000_0000_0000_0000;
let zvec: Vec<u8> = vec![0, 1, 2, 3, 4, 5, 6, 7];
let zset_from_zvec = zvec2zset_rev(&zvec);
assert_eq!(zset_from_zvec, zset_int);
}
#[test]
fn zoom_set_into_zoom_vec() {
let zset_int_fwd: u32 = 0b0000_0000_0000_0000_0000_0000_1111_1111;
let zet_fwd_vec: Vec<u8> = ZoomSet::from(zset_int_fwd).into();
assert_eq!(zet_fwd_vec, vec![0, 1, 2, 3, 4, 5, 6, 7]);
let zset_int_rev: u32 = 0b1111_1111_1000_0000_0000_0000_0000_0000;
let zset: ZoomSet = zset_int_rev.into();
let zvec = Vec::from(zset);
assert_eq!(zvec, vec![0, 1, 2, 3, 4, 5, 6, 7]);
}
}