mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/item/storage.rs')
| -rw-r--r-- | src/item/storage.rs | 729 |
1 files changed, 356 insertions, 373 deletions
diff --git a/src/item/storage.rs b/src/item/storage.rs index 5f57b75..fd5be32 100644 --- a/src/item/storage.rs +++ b/src/item/storage.rs @@ -6,405 +6,388 @@ use std::slice; use crate::item; #[derive(Clone, Debug, Eq)] -pub struct Storage -{ - base: Vec<u32>, - total: u64, +pub struct Storage { + base: Vec<u32>, + total: u64, } -impl Storage -{ - pub const fn new() -> Self - { - Self{base: Vec::new(), total: 0} - } - - pub fn is_empty(&self) -> bool - { - self.total == 0 - } - - pub fn get_total(&self) -> u64 - { - self.total - } - - pub fn get(&self, ty: item::Type) -> u32 - { - match self.base.get(u16::from(ty) as usize) - { - None => 0, - Some(cnt) => *cnt, - } - } - - pub fn set(&mut self, ty: item::Type, count: u32) -> u32 - { - let idx = u16::from(ty) as usize; - match self.base.get_mut(idx) - { - None => - { - self.base.resize(idx + 1, 0); - self.base[idx] = count; - self.total += count as u64; - 0 - }, - Some(curr) => - { - let prev = *curr; - self.total = self.total - prev as u64 + count as u64; - *curr = count; - prev - }, - } - } - - pub fn add(&mut self, ty: item::Type, add: u32, max: u32) -> (u32, u32) - { - let idx = u16::from(ty) as usize; - match self.base.get_mut(idx) - { - None => - { - let actual = add.min(max); - self.base.resize(idx + 1, 0); - self.base[idx] = actual; - self.total += add as u64; - (actual, actual) - } - Some(curr) => - { - if *curr < max - { - let actual = add.min(max - *curr); - *curr += actual; - self.total += actual as u64; - (actual, *curr) - } - else {(0, *curr)} - }, - } - } - - pub fn try_add(&mut self, ty: item::Type, add: u32, max: u32) -> Result<(u32, u32), TryAddError> - { - let idx = u16::from(ty) as usize; - match self.base.get_mut(idx) - { - None => - { - if add <= max - { - self.base.resize(idx + 1, 0); - self.base[idx] = add; - self.total += add as u64; - Ok((add, add)) - } - else {Err(TryAddError{ty, have: 0, add, max})} - }, - Some(curr) => - { - if *curr <= max && max - *curr <= add - { - *curr += add; - self.total += add as u64; - Ok((add, *curr)) - } - else {Err(TryAddError{ty, have: *curr, add, max})} - }, - } - } - - pub fn sub(&mut self, ty: item::Type, sub: u32, min: u32) -> (u32, u32) - { - match self.base.get_mut(u16::from(ty) as usize) - { - None => (0, 0), - Some(curr) => - { - if *curr > min - { - let actual = sub.min(*curr - min); - *curr -= actual; - self.total -= actual as u64; - (actual, *curr) - } - else {(0, *curr)} - }, - } - } - - pub fn try_sub(&mut self, ty: item::Type, sub: u32, min: u32) -> Result<(u32, u32), TrySubError> - { - let idx = u16::from(ty) as usize; - match self.base.get_mut(idx) - { - None => Err(TrySubError{ty, have: 0, sub, min}), - Some(curr) => - { - if *curr >= min && *curr - min >= sub - { - *curr -= sub; - self.total -= sub as u64; - Ok((sub, *curr)) - } - else {Err(TrySubError{ty, have: *curr, sub, min})} - }, - } - } - - pub fn add_all(&mut self, other: &Storage, max_each: u32) -> (u64, u64) - { - let mut added = 0u64; - if max_each > 0 && other.get_total() > 0 - { - let mut iter = other.base.iter().enumerate(); - // resize our vector only once and if necessary - let (last, add_last) = iter.rfind(|(_, n)| **n != 0).unwrap(); - if self.base.len() <= last - { - self.base.resize(last + 1, 0); - } - // process items by increasing ID - for (idx, add) in iter - { - let curr = self.base[idx]; - if curr < max_each - { - let actual = (*add).min(max_each - curr); - self.base[idx] += actual; - added += actual as u64; - } - } - // process the final element (which we've retrieved first) - let curr = self.base[last]; - if curr < max_each - { - let actual = (*add_last).min(max_each - curr); - self.base[last] += actual; - added += actual as u64; - } - // update total - self.total += added; - } - (added, self.total) - } - - pub fn pull_all(&mut self, other: &mut Storage, max_each: u32) -> (u64, u64, u64) - { - let mut added = 0u64; - if max_each > 0 && other.get_total() > 0 - { - let mut iter = other.base.iter_mut().enumerate(); - // resize our vector only once and if necessary - let (last, add_last) = iter.rfind(|(_, n)| **n != 0).unwrap(); - if self.base.len() <= last - { - self.base.resize(last + 1, 0); - } - // process items by increasing ID - for (idx, add) in iter - { - let curr = self.base[idx]; - if curr < max_each - { - let actual = (*add).min(max_each - curr); - self.base[idx] += actual; - *add -= actual; - added += actual as u64; - } - } - // process the final element (which we've retrieved first) - let curr = self.base[last]; - if curr < max_each - { - let actual = (*add_last).min(max_each - curr); - self.base[last] += actual; - *add_last -= actual; - added += actual as u64; - } - // update totals - self.total += added; - other.total -= added; - } - (added, self.total, other.total) - } - - pub fn sub_all(&mut self, other: &Storage, min_each: u32) -> (u64, u64) - { - let mut subbed = 0u64; - if self.get_total() > 0 && other.get_total() > 0 - { - // no need for resizing, we only remove - // process items by increasing ID - for (idx, sub) in other.base.iter().enumerate() - { - if let Some(curr) = self.base.get(idx) - { - if *curr > min_each - { - let actual = (*sub).min(*curr - min_each); - self.base[idx] -= actual; - subbed += actual as u64; - } - } - else {break;} - } - // update total - self.total -= subbed; - } - (subbed, self.total) - } - - pub fn diff_all(&mut self, other: &mut Storage, min_each: u32) -> (u64, u64, u64) - { - let mut subbed = 0u64; - if self.get_total() > 0 && other.get_total() > 0 - { - // no need for resizing, we only remove - // consider only indexes present in both - let end = self.base.len().min(other.base.len()); - let lhs = &mut self.base[..end]; - let rhs = &mut other.base[..end]; - // process items by increasing ID - for (l, r) in lhs.into_iter().zip(rhs) - { - if *l > min_each && *r > min_each - { - let actual = (*l - min_each).min(*r - min_each); - *l -= actual; - *r -= actual; - subbed -= actual as u64; - } - } - // update totals - self.total -= subbed; - other.total -= subbed; - } - (subbed, self.total, other.total) - } - - pub fn iter<'s>(&'s self) -> Iter<'s> - { - Iter{base: self.base.iter().enumerate(), all: true} - } - - pub fn iter_nonzero<'s>(&'s self) -> Iter<'s> - { - Iter{base: self.base.iter().enumerate(), all: false} - } - - pub fn clear(&mut self) - { - self.base.clear() - } +impl Storage { + pub const fn new() -> Self { + Self { + base: Vec::new(), + total: 0, + } + } + + pub fn is_empty(&self) -> bool { + self.total == 0 + } + + pub fn get_total(&self) -> u64 { + self.total + } + + pub fn get(&self, ty: item::Type) -> u32 { + match self.base.get(u16::from(ty) as usize) { + None => 0, + Some(cnt) => *cnt, + } + } + + pub fn set(&mut self, ty: item::Type, count: u32) -> u32 { + let idx = u16::from(ty) as usize; + match self.base.get_mut(idx) { + None => { + self.base.resize(idx + 1, 0); + self.base[idx] = count; + self.total += count as u64; + 0 + } + Some(curr) => { + let prev = *curr; + self.total = self.total - prev as u64 + count as u64; + *curr = count; + prev + } + } + } + + pub fn add(&mut self, ty: item::Type, add: u32, max: u32) -> (u32, u32) { + let idx = u16::from(ty) as usize; + match self.base.get_mut(idx) { + None => { + let actual = add.min(max); + self.base.resize(idx + 1, 0); + self.base[idx] = actual; + self.total += add as u64; + (actual, actual) + } + Some(curr) => { + if *curr < max { + let actual = add.min(max - *curr); + *curr += actual; + self.total += actual as u64; + (actual, *curr) + } else { + (0, *curr) + } + } + } + } + + pub fn try_add( + &mut self, + ty: item::Type, + add: u32, + max: u32, + ) -> Result<(u32, u32), TryAddError> { + let idx = u16::from(ty) as usize; + match self.base.get_mut(idx) { + None => { + if add <= max { + self.base.resize(idx + 1, 0); + self.base[idx] = add; + self.total += add as u64; + Ok((add, add)) + } else { + Err(TryAddError { + ty, + have: 0, + add, + max, + }) + } + } + Some(curr) => { + if *curr <= max && max - *curr <= add { + *curr += add; + self.total += add as u64; + Ok((add, *curr)) + } else { + Err(TryAddError { + ty, + have: *curr, + add, + max, + }) + } + } + } + } + + pub fn sub(&mut self, ty: item::Type, sub: u32, min: u32) -> (u32, u32) { + match self.base.get_mut(u16::from(ty) as usize) { + None => (0, 0), + Some(curr) => { + if *curr > min { + let actual = sub.min(*curr - min); + *curr -= actual; + self.total -= actual as u64; + (actual, *curr) + } else { + (0, *curr) + } + } + } + } + + pub fn try_sub( + &mut self, + ty: item::Type, + sub: u32, + min: u32, + ) -> Result<(u32, u32), TrySubError> { + let idx = u16::from(ty) as usize; + match self.base.get_mut(idx) { + None => Err(TrySubError { + ty, + have: 0, + sub, + min, + }), + Some(curr) => { + if *curr >= min && *curr - min >= sub { + *curr -= sub; + self.total -= sub as u64; + Ok((sub, *curr)) + } else { + Err(TrySubError { + ty, + have: *curr, + sub, + min, + }) + } + } + } + } + + pub fn add_all(&mut self, other: &Storage, max_each: u32) -> (u64, u64) { + let mut added = 0u64; + if max_each > 0 && other.get_total() > 0 { + let mut iter = other.base.iter().enumerate(); + // resize our vector only once and if necessary + let (last, add_last) = iter.rfind(|(_, n)| **n != 0).unwrap(); + if self.base.len() <= last { + self.base.resize(last + 1, 0); + } + // process items by increasing ID + for (idx, add) in iter { + let curr = self.base[idx]; + if curr < max_each { + let actual = (*add).min(max_each - curr); + self.base[idx] += actual; + added += actual as u64; + } + } + // process the final element (which we've retrieved first) + let curr = self.base[last]; + if curr < max_each { + let actual = (*add_last).min(max_each - curr); + self.base[last] += actual; + added += actual as u64; + } + // update total + self.total += added; + } + (added, self.total) + } + + pub fn pull_all(&mut self, other: &mut Storage, max_each: u32) -> (u64, u64, u64) { + let mut added = 0u64; + if max_each > 0 && other.get_total() > 0 { + let mut iter = other.base.iter_mut().enumerate(); + // resize our vector only once and if necessary + let (last, add_last) = iter.rfind(|(_, n)| **n != 0).unwrap(); + if self.base.len() <= last { + self.base.resize(last + 1, 0); + } + // process items by increasing ID + for (idx, add) in iter { + let curr = self.base[idx]; + if curr < max_each { + let actual = (*add).min(max_each - curr); + self.base[idx] += actual; + *add -= actual; + added += actual as u64; + } + } + // process the final element (which we've retrieved first) + let curr = self.base[last]; + if curr < max_each { + let actual = (*add_last).min(max_each - curr); + self.base[last] += actual; + *add_last -= actual; + added += actual as u64; + } + // update totals + self.total += added; + other.total -= added; + } + (added, self.total, other.total) + } + + pub fn sub_all(&mut self, other: &Storage, min_each: u32) -> (u64, u64) { + let mut subbed = 0u64; + if self.get_total() > 0 && other.get_total() > 0 { + // no need for resizing, we only remove + // process items by increasing ID + for (idx, sub) in other.base.iter().enumerate() { + if let Some(curr) = self.base.get(idx) { + if *curr > min_each { + let actual = (*sub).min(*curr - min_each); + self.base[idx] -= actual; + subbed += actual as u64; + } + } else { + break; + } + } + // update total + self.total -= subbed; + } + (subbed, self.total) + } + + pub fn diff_all(&mut self, other: &mut Storage, min_each: u32) -> (u64, u64, u64) { + let mut subbed = 0u64; + if self.get_total() > 0 && other.get_total() > 0 { + // no need for resizing, we only remove + // consider only indexes present in both + let end = self.base.len().min(other.base.len()); + let lhs = &mut self.base[..end]; + let rhs = &mut other.base[..end]; + // process items by increasing ID + for (l, r) in lhs.into_iter().zip(rhs) { + if *l > min_each && *r > min_each { + let actual = (*l - min_each).min(*r - min_each); + *l -= actual; + *r -= actual; + subbed -= actual as u64; + } + } + // update totals + self.total -= subbed; + other.total -= subbed; + } + (subbed, self.total, other.total) + } + + pub fn iter<'s>(&'s self) -> Iter<'s> { + Iter { + base: self.base.iter().enumerate(), + all: true, + } + } + + pub fn iter_nonzero<'s>(&'s self) -> Iter<'s> { + Iter { + base: self.base.iter().enumerate(), + all: false, + } + } + + pub fn clear(&mut self) { + self.base.clear() + } } // manual because padding with zeros doesn't affect equality -impl PartialEq for Storage -{ - fn eq(&self, other: &Self) -> bool - { - let mut li = self.base.iter().fuse(); - let mut ri = other.base.iter().fuse(); - loop - { - match (li.next(), ri.next()) - { - (None, None) => return true, - (l, r) => - { - if l.unwrap_or(&0) != r.unwrap_or(&0) {return false;} - }, - } - } - } +impl PartialEq for Storage { + fn eq(&self, other: &Self) -> bool { + let mut li = self.base.iter().fuse(); + let mut ri = other.base.iter().fuse(); + loop { + match (li.next(), ri.next()) { + (None, None) => return true, + (l, r) => { + if l.unwrap_or(&0) != r.unwrap_or(&0) { + return false; + } + } + } + } + } } -impl fmt::Display for Storage -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result - { - let mut first = true; - for (ty, cnt) in self.iter_nonzero() - { - if first {first = false;} - else {f.write_str(", ")?;} - write!(f, "{cnt} {ty}")?; - } - Ok(()) - } +impl fmt::Display for Storage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut first = true; + for (ty, cnt) in self.iter_nonzero() { + if first { + first = false; + } else { + f.write_str(", ")?; + } + write!(f, "{cnt} {ty}")?; + } + Ok(()) + } } #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct TryAddError -{ - pub ty: item::Type, - pub have: u32, - pub add: u32, - pub max: u32 +pub struct TryAddError { + pub ty: item::Type, + pub have: u32, + pub add: u32, + pub max: u32, } -impl fmt::Display for TryAddError -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result - { - write!(f, "adding {} {:?} to current {} would exceed {}", self.add, self.ty, self.have, self.max) - } +impl fmt::Display for TryAddError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "adding {} {:?} to current {} would exceed {}", + self.add, self.ty, self.have, self.max + ) + } } impl Error for TryAddError {} #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct TrySubError -{ - pub ty: item::Type, - pub have: u32, - pub sub: u32, - pub min: u32 +pub struct TrySubError { + pub ty: item::Type, + pub have: u32, + pub sub: u32, + pub min: u32, } -impl fmt::Display for TrySubError -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result - { - write!(f, "removing {} {:?} from current {} would drop below {}", self.sub, self.ty, self.have, self.min) - } +impl fmt::Display for TrySubError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "removing {} {:?} from current {} would drop below {}", + self.sub, self.ty, self.have, self.min + ) + } } impl Error for TrySubError {} #[derive(Clone, Debug)] -pub struct Iter<'l> -{ - base: Enumerate<slice::Iter<'l, u32>>, - all: bool, +pub struct Iter<'l> { + base: Enumerate<slice::Iter<'l, u32>>, + all: bool, } -impl<'l> Iterator for Iter<'l> -{ - type Item = (item::Type, u32); - - fn next(&mut self) -> Option<Self::Item> - { - while let Some((idx, cnt)) = self.base.next() - { - if *cnt > 0 || self.all - { - if let Ok(ty) = item::Type::try_from(idx as u16) - { - return Some((ty, *cnt)); - } - } - } - None - } - - fn size_hint(&self) -> (usize, Option<usize>) - { - (0, self.base.size_hint().1) - } +impl<'l> Iterator for Iter<'l> { + type Item = (item::Type, u32); + + fn next(&mut self) -> Option<Self::Item> { + while let Some((idx, cnt)) = self.base.next() { + if *cnt > 0 || self.all { + if let Ok(ty) = item::Type::try_from(idx as u16) { + return Some((ty, *cnt)); + } + } + } + None + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (0, self.base.size_hint().1) + } } impl<'l> FusedIterator for Iter<'l> where Enumerate<slice::Iter<'l, u32>>: FusedIterator {} |