adx: undo custom formatting

This commit is contained in:
Harsh Shandilya 2022-04-20 06:03:39 +05:30
parent 79c2a49834
commit dafee9a48b
No known key found for this signature in database
GPG Key ID: 366D7BBAD1031E80
6 changed files with 466 additions and 508 deletions

View File

@ -12,151 +12,149 @@ use thiserror::Error;
/// order.
#[derive(Debug, Eq, PartialEq, PartialOrd, Clone, Copy)]
pub(crate) enum Channel {
Dev,
Alpha,
Beta,
Rc,
Stable,
Dev,
Alpha,
Beta,
Rc,
Stable,
}
#[derive(Debug, Error)]
pub(crate) enum ChannelError {
#[error("no match found")]
NoMatchFound,
#[error("failed to determine channel for {0}")]
FailedToParseVersion(Version),
#[error("no match found")]
NoMatchFound,
#[error("failed to determine channel for {0}")]
FailedToParseVersion(Version),
}
impl FromStr for Channel {
type Err = ChannelError;
type Err = ChannelError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"alpha" | "a" => Ok(Channel::Alpha),
"beta" | "b" => Ok(Channel::Beta),
"dev" | "d" => Ok(Channel::Dev),
"rc" | "r" => Ok(Channel::Rc),
"stable" | "s" => Ok(Channel::Stable),
_ => Err(ChannelError::NoMatchFound),
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"alpha" | "a" => Ok(Channel::Alpha),
"beta" | "b" => Ok(Channel::Beta),
"dev" | "d" => Ok(Channel::Dev),
"rc" | "r" => Ok(Channel::Rc),
"stable" | "s" => Ok(Channel::Stable),
_ => Err(ChannelError::NoMatchFound),
}
}
}
}
impl TryFrom<Version> for Channel {
type Error = ChannelError;
type Error = ChannelError;
fn try_from(value: Version) -> Result<Self, Self::Error> {
if value.pre == Prerelease::EMPTY {
Ok(Channel::Stable)
} else {
let pre_str = value.pre.to_string();
if pre_str.starts_with("alpha") {
Ok(Channel::Alpha)
} else if pre_str.starts_with("beta") {
Ok(Channel::Beta)
} else if pre_str.starts_with("dev") {
Ok(Channel::Dev)
} else if pre_str.starts_with("rc") {
Ok(Channel::Rc)
} else {
Err(ChannelError::FailedToParseVersion(value))
}
fn try_from(value: Version) -> Result<Self, Self::Error> {
if value.pre == Prerelease::EMPTY {
Ok(Channel::Stable)
} else {
let pre_str = value.pre.to_string();
if pre_str.starts_with("alpha") {
Ok(Channel::Alpha)
} else if pre_str.starts_with("beta") {
Ok(Channel::Beta)
} else if pre_str.starts_with("dev") {
Ok(Channel::Dev)
} else if pre_str.starts_with("rc") {
Ok(Channel::Rc)
} else {
Err(ChannelError::FailedToParseVersion(value))
}
}
}
}
}
#[cfg(test)]
mod tests {
use std::convert::TryFrom;
use std::convert::TryFrom;
use semver::{BuildMetadata, Prerelease, Version};
use semver::{BuildMetadata, Prerelease, Version};
use super::Channel;
use super::Channel;
#[test]
fn alpha_version() {
let v = Version {
major: 1,
minor: 1,
patch: 0,
pre: Prerelease::new("alpha01").unwrap(),
build: BuildMetadata::EMPTY,
};
let channel = Channel::try_from(v);
assert_eq!(Channel::Alpha, channel.unwrap());
}
#[test]
fn alpha_version() {
let v = Version {
major: 1,
minor: 1,
patch: 0,
pre: Prerelease::new("alpha01").unwrap(),
build: BuildMetadata::EMPTY,
};
let channel = Channel::try_from(v);
assert_eq!(Channel::Alpha, channel.unwrap());
}
#[test]
fn beta_version() {
let v = Version {
major: 1,
minor: 1,
patch: 0,
pre: Prerelease::new("beta01").unwrap(),
build: BuildMetadata::EMPTY,
};
let channel = Channel::try_from(v);
assert_eq!(Channel::Beta, channel.unwrap());
}
#[test]
fn beta_version() {
let v = Version {
major: 1,
minor: 1,
patch: 0,
pre: Prerelease::new("beta01").unwrap(),
build: BuildMetadata::EMPTY,
};
let channel = Channel::try_from(v);
assert_eq!(Channel::Beta, channel.unwrap());
}
#[test]
fn dev_version() {
let v = Version {
major: 1,
minor: 1,
patch: 0,
pre: Prerelease::new("dev01").unwrap(),
build: BuildMetadata::EMPTY,
};
let channel = Channel::try_from(v);
assert_eq!(Channel::Dev, channel.unwrap());
}
#[test]
fn dev_version() {
let v = Version {
major: 1,
minor: 1,
patch: 0,
pre: Prerelease::new("dev01").unwrap(),
build: BuildMetadata::EMPTY,
};
let channel = Channel::try_from(v);
assert_eq!(Channel::Dev, channel.unwrap());
}
#[test]
fn rc_version() {
let v = Version {
major: 1,
minor: 1,
patch: 0,
pre: Prerelease::new("rc01").unwrap(),
build: BuildMetadata::EMPTY,
};
let channel = Channel::try_from(v);
assert_eq!(Channel::Rc, channel.unwrap());
}
#[test]
fn rc_version() {
let v = Version {
major: 1,
minor: 1,
patch: 0,
pre: Prerelease::new("rc01").unwrap(),
build: BuildMetadata::EMPTY,
};
let channel = Channel::try_from(v);
assert_eq!(Channel::Rc, channel.unwrap());
}
#[test]
fn stable_version() {
let v = Version::new(1, 1, 1);
let channel = Channel::try_from(v);
assert_eq!(Channel::Stable, channel.unwrap());
}
#[test]
fn stable_version() {
let v = Version::new(1, 1, 1);
let channel = Channel::try_from(v);
assert_eq!(Channel::Stable, channel.unwrap());
}
#[test]
fn cmp_channels() {
assert!(Channel::Stable > Channel::Rc);
assert!(Channel::Rc > Channel::Beta);
assert!(Channel::Beta > Channel::Alpha);
assert!(Channel::Alpha > Channel::Dev);
}
#[test]
fn cmp_channels() {
assert!(Channel::Stable > Channel::Rc);
assert!(Channel::Rc > Channel::Beta);
assert!(Channel::Beta > Channel::Alpha);
assert!(Channel::Alpha > Channel::Dev);
}
#[test]
fn cmp_parsed_versions() {
let stable = Channel::try_from(Version::parse("1.1.0").unwrap()).unwrap();
let rc = Channel::try_from(Version::parse("1.1.0-rc01").unwrap()).unwrap();
let alpha =
Channel::try_from(Version::parse("1.1.0-alpha01").unwrap()).unwrap();
let beta =
Channel::try_from(Version::parse("1.1.0-beta01").unwrap()).unwrap();
assert!(Channel::Stable >= stable);
assert!(Channel::Stable >= rc);
assert!(Channel::Stable >= alpha);
assert!(Channel::Stable >= beta);
assert!(Channel::Rc >= rc);
assert!(Channel::Rc >= beta);
assert!(Channel::Rc >= alpha);
assert!(Channel::Beta >= beta);
assert!(Channel::Beta >= alpha);
assert!(Channel::Alpha >= alpha);
}
#[test]
fn cmp_parsed_versions() {
let stable = Channel::try_from(Version::parse("1.1.0").unwrap()).unwrap();
let rc = Channel::try_from(Version::parse("1.1.0-rc01").unwrap()).unwrap();
let alpha = Channel::try_from(Version::parse("1.1.0-alpha01").unwrap()).unwrap();
let beta = Channel::try_from(Version::parse("1.1.0-beta01").unwrap()).unwrap();
assert!(Channel::Stable >= stable);
assert!(Channel::Stable >= rc);
assert!(Channel::Stable >= alpha);
assert!(Channel::Stable >= beta);
assert!(Channel::Rc >= rc);
assert!(Channel::Rc >= beta);
assert!(Channel::Rc >= alpha);
assert!(Channel::Beta >= beta);
assert!(Channel::Beta >= alpha);
assert!(Channel::Alpha >= alpha);
}
}

View File

@ -21,33 +21,33 @@ static GLOBAL: &StatsAlloc<System> = &INSTRUMENTED_SYSTEM;
#[clap(author, version, about)]
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
pub(crate) struct Cli {
/// search term to filter packages with
#[cfg(not(feature = "measure-alloc"))]
#[clap(required = true)]
pub(crate) search_term: String,
/// the release channel to find packages from
#[clap(short='c', long="channel", possible_values=&["alpha", "a", "beta", "b", "dev", "d", "rc", "r", "stable", "s"], default_value="a")]
pub(crate) channel: Channel,
/// search term to filter packages with
#[cfg(not(feature = "measure-alloc"))]
#[clap(required = true)]
pub(crate) search_term: String,
/// the release channel to find packages from
#[clap(short='c', long="channel", possible_values=&["alpha", "a", "beta", "b", "dev", "d", "rc", "r", "stable", "s"], default_value="a")]
pub(crate) channel: Channel,
}
#[tokio::main]
async fn main() -> Result<()> {
color_eyre::install()?;
#[cfg(feature = "measure-alloc")]
let reg = Region::new(GLOBAL);
let cli = Cli::parse();
#[cfg(feature = "measure-alloc")]
let packages = crate::parse::parse("", cli.channel).await?;
#[cfg(not(feature = "measure-alloc"))]
let packages = crate::parse::parse(&cli.search_term, cli.channel).await?;
if packages.is_empty() {
println!("No results found!");
} else {
for package in &packages {
println!("{}", package);
}
};
#[cfg(feature = "measure-alloc")]
println!("{:#?}", reg.change());
Ok(())
color_eyre::install()?;
#[cfg(feature = "measure-alloc")]
let reg = Region::new(GLOBAL);
let cli = Cli::parse();
#[cfg(feature = "measure-alloc")]
let packages = crate::parse::parse("", cli.channel).await?;
#[cfg(not(feature = "measure-alloc"))]
let packages = crate::parse::parse(&cli.search_term, cli.channel).await?;
if packages.is_empty() {
println!("No results found!");
} else {
for package in &packages {
println!("{}", package);
}
};
#[cfg(feature = "measure-alloc")]
println!("{:#?}", reg.change());
Ok(())
}

View File

@ -3,17 +3,17 @@ use std::fmt::{Debug, Display, Formatter, Result};
/// Struct that represents a Maven package
#[derive(Debug)]
pub(crate) struct MavenPackage {
pub(crate) group_id: String,
pub(crate) artifact_id: String,
pub(crate) latest_version: String,
pub(crate) group_id: String,
pub(crate) artifact_id: String,
pub(crate) latest_version: String,
}
impl Display for MavenPackage {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(
f,
"{}:{}:{}",
self.group_id, self.artifact_id, self.latest_version,
)
}
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(
f,
"{}:{}:{}",
self.group_id, self.artifact_id, self.latest_version,
)
}
}

View File

@ -16,7 +16,27 @@ const BASE_MAVEN_URL: &str = "https://dl.google.com/dl/android/maven2";
/// and returns the XML as a String
#[cfg(not(test))]
async fn get_maven_index() -> Result<String> {
reqwest::get(format!("{}/master-index.xml", BASE_MAVEN_URL))
reqwest::get(format!("{}/master-index.xml", BASE_MAVEN_URL))
.await?
.text()
.await
.map_err(|e| eyre!(e))
}
#[cfg(test)]
#[allow(clippy::unused_async)]
async fn get_maven_index() -> Result<String> {
std::fs::read_to_string("../testdata/master-index.xml").map_err(|e| eyre!(e))
}
/// Downloads the group index for the given group.
#[cfg(not(test))]
async fn get_group_index(group: &str) -> Result<String> {
reqwest::get(format!(
"{}/{}/group-index.xml",
BASE_MAVEN_URL,
group.replace('.', "/")
))
.await?
.text()
.await
@ -25,158 +45,123 @@ async fn get_maven_index() -> Result<String> {
#[cfg(test)]
#[allow(clippy::unused_async)]
async fn get_maven_index() -> Result<String> {
std::fs::read_to_string("../testdata/master-index.xml").map_err(|e| eyre!(e))
}
/// Downloads the group index for the given group.
#[cfg(not(test))]
async fn get_group_index(group: &str) -> Result<String> {
reqwest::get(format!(
"{}/{}/group-index.xml",
BASE_MAVEN_URL,
group.replace('.', "/")
))
.await?
.text()
.await
.map_err(|e| eyre!(e))
}
#[cfg(test)]
#[allow(clippy::unused_async)]
async fn get_group_index(group: &str) -> Result<String> {
std::fs::read_to_string(format!("../testdata/{}.xml", group))
.map_err(|e| eyre!(e))
std::fs::read_to_string(format!("../testdata/{}.xml", group)).map_err(|e| eyre!(e))
}
/// Parses a given master-index.xml and filters the found packages based on
// `search_term`.
fn filter_groups(doc: &Document<'_>, search_term: &str) -> Vec<String> {
let mut groups = vec![];
for node in doc
.descendants()
// Only keep elements
.filter(|node| node.node_type() == NodeType::Element)
// Skip the first one since it is junk
.skip(1)
{
let tag = node.tag_name().name();
if tag.contains(search_term) {
groups.push(tag.to_string());
let mut groups = vec![];
for node in doc
.descendants()
// Only keep elements
.filter(|node| node.node_type() == NodeType::Element)
// Skip the first one since it is junk
.skip(1)
{
let tag = node.tag_name().name();
if tag.contains(search_term) {
groups.push(tag.to_string());
}
}
}
groups
groups
}
/// Given a list of groups, returns a `Vec<MavenPackage>` of all artifacts.
async fn parse_packages(
groups: Vec<String>,
channel: Channel,
) -> Result<Vec<MavenPackage>> {
// Create a Vec<Future<_>>, this will allow us to run all tasks together
// without requiring us to spawn a new thread
let group_futures = groups
.iter()
.map(|group_name| parse_group(group_name, channel));
async fn parse_packages(groups: Vec<String>, channel: Channel) -> Result<Vec<MavenPackage>> {
// Create a Vec<Future<_>>, this will allow us to run all tasks together
// without requiring us to spawn a new thread
let group_futures = groups
.iter()
.map(|group_name| parse_group(group_name, channel));
// Wait for all groups to complete to get a Vec<Vec<MavenPackage>>
let merged_list = join_all(group_futures).await;
// Wait for all groups to complete to get a Vec<Vec<MavenPackage>>
let merged_list = join_all(group_futures).await;
Ok(
merged_list
.into_iter()
.filter_map(std::result::Result::ok)
.flatten()
.collect(),
)
Ok(merged_list
.into_iter()
.filter_map(std::result::Result::ok)
.flatten()
.collect())
}
/// Given a group, returns a `Vec<MavenPackage>` of all artifacts from this
/// group.
async fn parse_group(
group_name: &str,
channel: Channel,
) -> Result<Vec<MavenPackage>> {
let group_index = get_group_index(group_name).await?;
let doc = Document::parse(&group_index)
.map_err(|e| eyre!(e).with_note(|| format!("group_name={}", group_name)))?;
Ok(
doc
.descendants()
.filter(|node| node.node_type() == NodeType::Element)
.filter(|node| node.tag_name().name() == group_name)
.flat_map(|node| {
node
.children()
.filter(|node| node.node_type() == NodeType::Element)
.filter_map(|node| {
let mut versions = node
.attribute("versions")
.unwrap()
.split(',')
.filter_map(|v| Version::parse(v).ok())
.filter(|v| {
if let Ok(c) = Channel::try_from(v.clone()) {
c >= channel
} else {
false
}
})
.collect::<Vec<Version>>();
if versions.is_empty() {
None
} else {
versions.sort_by(|a, b| b.partial_cmp(a).unwrap());
Some(MavenPackage {
group_id: String::from(group_name),
artifact_id: node.tag_name().name().to_string(),
latest_version: versions.get(0).unwrap().to_string(),
})
}
})
.collect::<Vec<MavenPackage>>()
})
.collect(),
)
async fn parse_group(group_name: &str, channel: Channel) -> Result<Vec<MavenPackage>> {
let group_index = get_group_index(group_name).await?;
let doc = Document::parse(&group_index)
.map_err(|e| eyre!(e).with_note(|| format!("group_name={}", group_name)))?;
Ok(doc
.descendants()
.filter(|node| node.node_type() == NodeType::Element)
.filter(|node| node.tag_name().name() == group_name)
.flat_map(|node| {
node.children()
.filter(|node| node.node_type() == NodeType::Element)
.filter_map(|node| {
let mut versions = node
.attribute("versions")
.unwrap()
.split(',')
.filter_map(|v| Version::parse(v).ok())
.filter(|v| {
if let Ok(c) = Channel::try_from(v.clone()) {
c >= channel
} else {
false
}
})
.collect::<Vec<Version>>();
if versions.is_empty() {
None
} else {
versions.sort_by(|a, b| b.partial_cmp(a).unwrap());
Some(MavenPackage {
group_id: String::from(group_name),
artifact_id: node.tag_name().name().to_string(),
latest_version: versions.get(0).unwrap().to_string(),
})
}
})
.collect::<Vec<MavenPackage>>()
})
.collect())
}
pub(crate) async fn parse(
search_term: &str,
channel: Channel,
) -> Result<Vec<MavenPackage>> {
let maven_index = get_maven_index().await?;
let doc = Document::parse(&maven_index)?;
let groups = filter_groups(&doc, search_term);
parse_packages(groups, channel).await
pub(crate) async fn parse(search_term: &str, channel: Channel) -> Result<Vec<MavenPackage>> {
let maven_index = get_maven_index().await?;
let doc = Document::parse(&maven_index)?;
let groups = filter_groups(&doc, search_term);
parse_packages(groups, channel).await
}
#[cfg(test)]
mod test {
use color_eyre::eyre::eyre;
use futures::executor::block_on;
use color_eyre::eyre::eyre;
use futures::executor::block_on;
use super::{parse, Channel};
use super::{parse, Channel};
#[test]
fn check_filter_works() {
let res = block_on(parse("appcompat", Channel::Alpha))
.map_err(|e| eyre!(e))
.unwrap();
assert_eq!(res.len(), 2);
for pkg in &res {
assert_eq!(pkg.group_id, "androidx.appcompat");
#[test]
fn check_filter_works() {
let res = block_on(parse("appcompat", Channel::Alpha))
.map_err(|e| eyre!(e))
.unwrap();
assert_eq!(res.len(), 2);
for pkg in &res {
assert_eq!(pkg.group_id, "androidx.appcompat");
}
assert!(res.iter().any(|pkg| pkg.artifact_id == "appcompat"));
assert!(res
.iter()
.any(|pkg| pkg.artifact_id == "appcompat-resources"));
}
assert!(res.iter().any(|pkg| pkg.artifact_id == "appcompat"));
assert!(res
.iter()
.any(|pkg| pkg.artifact_id == "appcompat-resources"));
}
#[test]
fn check_all_packages_are_parsed() {
let res = block_on(parse("", Channel::Stable))
.expect("Parsing offline copies should always work");
assert_eq!(res.len(), 754);
}
#[test]
fn check_all_packages_are_parsed() {
let res = block_on(parse("", Channel::Stable))
.expect("Parsing offline copies should always work");
assert_eq!(res.len(), 754);
}
}

View File

@ -26,14 +26,14 @@
//! ```
#![deny(
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unused_import_braces,
unused_imports,
unused_qualifications,
missing_docs
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unused_import_braces,
unused_imports,
unused_qualifications,
missing_docs
)]
#![allow(dead_code, unsafe_code)]
#![cfg_attr(feature = "nightly", feature(const_fn))]
@ -48,261 +48,247 @@ use std::sync::atomic::{AtomicIsize, AtomicUsize, Ordering};
/// and reallocation requests to the underlying global allocator.
#[derive(Default, Debug)]
pub struct StatsAlloc<T: GlobalAlloc> {
allocations: AtomicUsize,
deallocations: AtomicUsize,
reallocations: AtomicUsize,
bytes_allocated: AtomicUsize,
bytes_deallocated: AtomicUsize,
bytes_reallocated: AtomicIsize,
inner: T,
allocations: AtomicUsize,
deallocations: AtomicUsize,
reallocations: AtomicUsize,
bytes_allocated: AtomicUsize,
bytes_deallocated: AtomicUsize,
bytes_reallocated: AtomicIsize,
inner: T,
}
/// Allocator statistics
#[derive(Clone, Copy, Default, Debug, Hash, PartialEq, Eq)]
pub struct Stats {
/// Count of allocation operations
pub allocations: usize,
/// Count of deallocation operations
pub deallocations: usize,
/// Count of reallocation operations
///
/// An example where reallocation may occur: resizing of a `Vec<T>` when
/// its length would excceed its capacity. Excessive reallocations may
/// indicate that resizable data structures are being created with
/// insufficient or poorly estimated initial capcities.
///
/// ```
/// let mut x = Vec::with_capacity(1);
/// x.push(0);
/// x.push(1); // Potential reallocation
/// ```
pub reallocations: usize,
/// Total bytes requested by allocations
pub bytes_allocated: usize,
/// Total bytes freed by deallocations
pub bytes_deallocated: usize,
/// Total of bytes requested minus bytes freed by reallocations
///
/// This number is positive if the total bytes requested by reallocation
/// operations is greater than the total bytes freed by reallocations. A
/// positive value indicates that resizable structures are growing, while
/// a negative value indicates that such structures are shrinking.
pub bytes_reallocated: isize,
/// Count of allocation operations
pub allocations: usize,
/// Count of deallocation operations
pub deallocations: usize,
/// Count of reallocation operations
///
/// An example where reallocation may occur: resizing of a `Vec<T>` when
/// its length would excceed its capacity. Excessive reallocations may
/// indicate that resizable data structures are being created with
/// insufficient or poorly estimated initial capcities.
///
/// ```
/// let mut x = Vec::with_capacity(1);
/// x.push(0);
/// x.push(1); // Potential reallocation
/// ```
pub reallocations: usize,
/// Total bytes requested by allocations
pub bytes_allocated: usize,
/// Total bytes freed by deallocations
pub bytes_deallocated: usize,
/// Total of bytes requested minus bytes freed by reallocations
///
/// This number is positive if the total bytes requested by reallocation
/// operations is greater than the total bytes freed by reallocations. A
/// positive value indicates that resizable structures are growing, while
/// a negative value indicates that such structures are shrinking.
pub bytes_reallocated: isize,
}
/// An instrumented instance of the system allocator.
pub static INSTRUMENTED_SYSTEM: StatsAlloc<System> = StatsAlloc {
allocations: AtomicUsize::new(0),
deallocations: AtomicUsize::new(0),
reallocations: AtomicUsize::new(0),
bytes_allocated: AtomicUsize::new(0),
bytes_deallocated: AtomicUsize::new(0),
bytes_reallocated: AtomicIsize::new(0),
inner: System,
allocations: AtomicUsize::new(0),
deallocations: AtomicUsize::new(0),
reallocations: AtomicUsize::new(0),
bytes_allocated: AtomicUsize::new(0),
bytes_deallocated: AtomicUsize::new(0),
bytes_reallocated: AtomicIsize::new(0),
inner: System,
};
impl StatsAlloc<System> {
/// Provides access to an instrumented instance of the system allocator.
pub const fn system() -> Self {
StatsAlloc {
allocations: AtomicUsize::new(0),
deallocations: AtomicUsize::new(0),
reallocations: AtomicUsize::new(0),
bytes_allocated: AtomicUsize::new(0),
bytes_deallocated: AtomicUsize::new(0),
bytes_reallocated: AtomicIsize::new(0),
inner: System,
/// Provides access to an instrumented instance of the system allocator.
pub const fn system() -> Self {
StatsAlloc {
allocations: AtomicUsize::new(0),
deallocations: AtomicUsize::new(0),
reallocations: AtomicUsize::new(0),
bytes_allocated: AtomicUsize::new(0),
bytes_deallocated: AtomicUsize::new(0),
bytes_reallocated: AtomicIsize::new(0),
inner: System,
}
}
}
}
impl<T: GlobalAlloc> StatsAlloc<T> {
/// Provides access to an instrumented instance of the given global
/// allocator.
#[cfg(feature = "nightly")]
pub const fn new(inner: T) -> Self {
StatsAlloc {
allocations: AtomicUsize::new(0),
deallocations: AtomicUsize::new(0),
reallocations: AtomicUsize::new(0),
bytes_allocated: AtomicUsize::new(0),
bytes_deallocated: AtomicUsize::new(0),
bytes_reallocated: AtomicIsize::new(0),
inner,
/// Provides access to an instrumented instance of the given global
/// allocator.
#[cfg(feature = "nightly")]
pub const fn new(inner: T) -> Self {
StatsAlloc {
allocations: AtomicUsize::new(0),
deallocations: AtomicUsize::new(0),
reallocations: AtomicUsize::new(0),
bytes_allocated: AtomicUsize::new(0),
bytes_deallocated: AtomicUsize::new(0),
bytes_reallocated: AtomicIsize::new(0),
inner,
}
}
}
/// Provides access to an instrumented instance of the given global
/// allocator.
#[cfg(not(feature = "nightly"))]
pub fn new(inner: T) -> Self {
StatsAlloc {
allocations: AtomicUsize::new(0),
deallocations: AtomicUsize::new(0),
reallocations: AtomicUsize::new(0),
bytes_allocated: AtomicUsize::new(0),
bytes_deallocated: AtomicUsize::new(0),
bytes_reallocated: AtomicIsize::new(0),
inner,
/// Provides access to an instrumented instance of the given global
/// allocator.
#[cfg(not(feature = "nightly"))]
pub fn new(inner: T) -> Self {
StatsAlloc {
allocations: AtomicUsize::new(0),
deallocations: AtomicUsize::new(0),
reallocations: AtomicUsize::new(0),
bytes_allocated: AtomicUsize::new(0),
bytes_deallocated: AtomicUsize::new(0),
bytes_reallocated: AtomicIsize::new(0),
inner,
}
}
}
/// Takes a snapshot of the current view of the allocator statistics.
pub fn stats(&self) -> Stats {
Stats {
allocations: self.allocations.load(Ordering::SeqCst),
deallocations: self.deallocations.load(Ordering::SeqCst),
reallocations: self.reallocations.load(Ordering::SeqCst),
bytes_allocated: self.bytes_allocated.load(Ordering::SeqCst),
bytes_deallocated: self.bytes_deallocated.load(Ordering::SeqCst),
bytes_reallocated: self.bytes_reallocated.load(Ordering::SeqCst),
/// Takes a snapshot of the current view of the allocator statistics.
pub fn stats(&self) -> Stats {
Stats {
allocations: self.allocations.load(Ordering::SeqCst),
deallocations: self.deallocations.load(Ordering::SeqCst),
reallocations: self.reallocations.load(Ordering::SeqCst),
bytes_allocated: self.bytes_allocated.load(Ordering::SeqCst),
bytes_deallocated: self.bytes_deallocated.load(Ordering::SeqCst),
bytes_reallocated: self.bytes_reallocated.load(Ordering::SeqCst),
}
}
}
}
impl ops::Sub for Stats {
type Output = Stats;
type Output = Stats;
fn sub(mut self, rhs: Self) -> Self::Output {
self -= rhs;
self
}
fn sub(mut self, rhs: Self) -> Self::Output {
self -= rhs;
self
}
}
impl ops::SubAssign for Stats {
fn sub_assign(&mut self, rhs: Self) {
self.allocations -= rhs.allocations;
self.deallocations -= rhs.deallocations;
self.reallocations -= rhs.reallocations;
self.bytes_allocated -= rhs.bytes_allocated;
self.bytes_deallocated -= rhs.bytes_deallocated;
self.bytes_reallocated -= rhs.bytes_reallocated;
}
fn sub_assign(&mut self, rhs: Self) {
self.allocations -= rhs.allocations;
self.deallocations -= rhs.deallocations;
self.reallocations -= rhs.reallocations;
self.bytes_allocated -= rhs.bytes_allocated;
self.bytes_deallocated -= rhs.bytes_deallocated;
self.bytes_reallocated -= rhs.bytes_reallocated;
}
}
/// A snapshot of the allocation statistics, which can be used to determine
/// allocation changes while the `Region` is alive.
#[derive(Debug)]
pub struct Region<'a, T: GlobalAlloc> {
alloc: &'a StatsAlloc<T>,
initial_stats: Stats,
alloc: &'a StatsAlloc<T>,
initial_stats: Stats,
}
impl<'a, T: GlobalAlloc + 'a> Region<'a, T> {
/// Creates a new region using statistics from the given instrumented
/// allocator.
#[inline]
pub fn new(alloc: &'a StatsAlloc<T>) -> Self {
Region {
alloc,
initial_stats: alloc.stats(),
/// Creates a new region using statistics from the given instrumented
/// allocator.
#[inline]
pub fn new(alloc: &'a StatsAlloc<T>) -> Self {
Region {
alloc,
initial_stats: alloc.stats(),
}
}
}
/// Returns the statistics as of instantiation or the last reset.
#[inline]
pub fn initial(&self) -> Stats {
self.initial_stats
}
/// Returns the statistics as of instantiation or the last reset.
#[inline]
pub fn initial(&self) -> Stats {
self.initial_stats
}
/// Returns the difference between the currently reported statistics and
/// those provided by `initial()`.
#[inline]
pub fn change(&self) -> Stats {
self.alloc.stats() - self.initial_stats
}
/// Returns the difference between the currently reported statistics and
/// those provided by `initial()`.
#[inline]
pub fn change(&self) -> Stats {
self.alloc.stats() - self.initial_stats
}
/// Returns the difference between the currently reported statistics and
/// those provided by `initial()`, resetting initial to the latest
/// reported statistics.
#[inline]
pub fn change_and_reset(&mut self) -> Stats {
let latest = self.alloc.stats();
let diff = latest - self.initial_stats;
self.initial_stats = latest;
diff
}
/// Returns the difference between the currently reported statistics and
/// those provided by `initial()`, resetting initial to the latest
/// reported statistics.
#[inline]
pub fn change_and_reset(&mut self) -> Stats {
let latest = self.alloc.stats();
let diff = latest - self.initial_stats;
self.initial_stats = latest;
diff
}
/// Resets the initial initial to the latest reported statistics from the
/// referenced allocator.
#[inline]
pub fn reset(&mut self) {
self.initial_stats = self.alloc.stats();
}
/// Resets the initial initial to the latest reported statistics from the
/// referenced allocator.
#[inline]
pub fn reset(&mut self) {
self.initial_stats = self.alloc.stats();
}
}
unsafe impl<'a, T: GlobalAlloc + 'a> GlobalAlloc for &'a StatsAlloc<T> {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
(*self).alloc(layout)
}
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
(*self).alloc(layout)
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
(*self).dealloc(ptr, layout)
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
(*self).dealloc(ptr, layout)
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
(*self).alloc_zeroed(layout)
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
(*self).alloc_zeroed(layout)
}
unsafe fn realloc(
&self,
ptr: *mut u8,
layout: Layout,
new_size: usize,
) -> *mut u8 {
(*self).realloc(ptr, layout, new_size)
}
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
(*self).realloc(ptr, layout, new_size)
}
}
unsafe impl<T: GlobalAlloc> GlobalAlloc for StatsAlloc<T> {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
self.allocations.fetch_add(1, Ordering::SeqCst);
self
.bytes_allocated
.fetch_add(layout.size(), Ordering::SeqCst);
self.inner.alloc(layout)
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
self.deallocations.fetch_add(1, Ordering::SeqCst);
self
.bytes_deallocated
.fetch_add(layout.size(), Ordering::SeqCst);
self.inner.dealloc(ptr, layout)
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
self.allocations.fetch_add(1, Ordering::SeqCst);
self
.bytes_allocated
.fetch_add(layout.size(), Ordering::SeqCst);
self.inner.alloc_zeroed(layout)
}
unsafe fn realloc(
&self,
ptr: *mut u8,
layout: Layout,
new_size: usize,
) -> *mut u8 {
self.reallocations.fetch_add(1, Ordering::SeqCst);
match new_size.cmp(&layout.size()) {
CmpOrdering::Greater => {
let difference = new_size - layout.size();
self.bytes_allocated.fetch_add(difference, Ordering::SeqCst);
}
CmpOrdering::Less => {
let difference = layout.size() - new_size;
self
.bytes_deallocated
.fetch_add(difference, Ordering::SeqCst);
}
_ => {}
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
self.allocations.fetch_add(1, Ordering::SeqCst);
self.bytes_allocated
.fetch_add(layout.size(), Ordering::SeqCst);
self.inner.alloc(layout)
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
self.deallocations.fetch_add(1, Ordering::SeqCst);
self.bytes_deallocated
.fetch_add(layout.size(), Ordering::SeqCst);
self.inner.dealloc(ptr, layout)
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
self.allocations.fetch_add(1, Ordering::SeqCst);
self.bytes_allocated
.fetch_add(layout.size(), Ordering::SeqCst);
self.inner.alloc_zeroed(layout)
}
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
self.reallocations.fetch_add(1, Ordering::SeqCst);
match new_size.cmp(&layout.size()) {
CmpOrdering::Greater => {
let difference = new_size - layout.size();
self.bytes_allocated.fetch_add(difference, Ordering::SeqCst);
}
CmpOrdering::Less => {
let difference = layout.size() - new_size;
self.bytes_deallocated
.fetch_add(difference, Ordering::SeqCst);
}
_ => {}
}
self.bytes_reallocated.fetch_add(
new_size.wrapping_sub(layout.size()) as isize,
Ordering::SeqCst,
);
self.inner.realloc(ptr, layout, new_size)
}
self.bytes_reallocated.fetch_add(
new_size.wrapping_sub(layout.size()) as isize,
Ordering::SeqCst,
);
self.inner.realloc(ptr, layout, new_size)
}
}

View File

@ -1,11 +0,0 @@
comment_width = 80
group_imports = "StdExternalCrate"
imports_granularity = "Module"
max_width = 80
newline_style = "Unix"
normalize_comments = true
normalize_doc_attributes = true
reorder_impl_items = true
tab_spaces = 2
version = "Two"
wrap_comments = true