use std::fmt;
use std::iter::FusedIterator;
use std::time::Duration;
use crate::{Builder, Counter, Group, ReadFormat};
used_in_docs!(Group);
used_in_docs!(Builder);
used_in_docs!(ReadFormat);
pub struct GroupData {
pub(crate) data: crate::data::ReadGroup<'static>,
values: Vec<u64>,
should_skip: bool,
}
impl GroupData {
pub(crate) fn new(data: crate::data::ReadGroup<'static>) -> Self {
let values = data.entries().map(|entry| entry.value()).collect();
Self {
data,
values,
should_skip: false,
}
}
pub fn len(&self) -> usize {
self.iter().len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn time_enabled(&self) -> Option<Duration> {
self.data.time_enabled().map(Duration::from_nanos)
}
pub fn time_running(&self) -> Option<Duration> {
self.data.time_running().map(Duration::from_nanos)
}
pub fn get(&self, member: &Counter) -> Option<GroupEntry> {
self.data.get_by_id(member.id()).map(GroupEntry)
}
pub fn iter(&self) -> GroupIter {
let mut iter = self.iter_with_group();
if self.should_skip {
let _ = iter.next();
}
iter
}
fn iter_with_group(&self) -> GroupIter {
GroupIter(self.data.entries())
}
pub(crate) fn skip_group(&mut self) {
self.should_skip = true;
}
}
impl std::ops::Index<&Counter> for GroupData {
type Output = u64;
fn index(&self, ctr: &Counter) -> &u64 {
let (index, _) = self
.iter_with_group()
.enumerate()
.find(|(_, entry)| entry.id() == ctr.id())
.unwrap_or_else(|| panic!("group contained no counter with id {}", ctr.id()));
&self.values[index]
}
}
impl fmt::Debug for GroupData {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
struct GroupEntries<'a>(&'a GroupData);
impl fmt::Debug for GroupEntries<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.0.iter()).finish()
}
}
let mut dbg = fmt.debug_struct("GroupData");
if let Some(time_enabled) = self.time_enabled() {
dbg.field("time_enabled", &time_enabled.as_nanos());
}
if let Some(time_running) = self.time_running() {
dbg.field("time_running", &time_running.as_nanos());
}
dbg.field("entries", &GroupEntries(self));
dbg.finish()
}
}
impl<'a> IntoIterator for &'a GroupData {
type IntoIter = GroupIter<'a>;
type Item = <GroupIter<'a> as Iterator>::Item;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[derive(Copy, Clone)]
pub struct GroupEntry(pub(crate) crate::data::GroupEntry);
impl GroupEntry {
pub fn value(&self) -> u64 {
self.0.value()
}
pub fn id(&self) -> u64 {
self.0.id().expect("group entry did not have an id")
}
pub fn lost(&self) -> Option<u64> {
self.0.lost()
}
}
impl fmt::Debug for GroupEntry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut dbg = f.debug_struct("GroupEntry");
dbg.field("value", &self.value());
dbg.field("id", &self.id());
if let Some(lost) = self.lost() {
dbg.field("lost", &lost);
}
dbg.finish_non_exhaustive()
}
}
#[derive(Clone)]
pub struct GroupIter<'a>(crate::data::GroupIter<'a>);
impl<'a> Iterator for GroupIter<'a> {
type Item = GroupEntry;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(GroupEntry)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
fn count(self) -> usize {
self.0.count()
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth(n).map(GroupEntry)
}
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
}
impl<'a> DoubleEndedIterator for GroupIter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back().map(GroupEntry)
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth_back(n).map(GroupEntry)
}
}
impl<'a> ExactSizeIterator for GroupIter<'a> {
fn len(&self) -> usize {
self.0.len()
}
}
impl<'a> FusedIterator for GroupIter<'a> {}