Full Code of magnet/metered-rs for AI

master f0d878e0042e cached
39 files
122.1 KB
31.0k tokens
232 symbols
1 requests
Download .txt
Repository: magnet/metered-rs
Branch: master
Commit: f0d878e0042e
Files: 39
Total size: 122.1 KB

Directory structure:
gitextract_mcq7nbdx/

├── .cargo/
│   └── config
├── .gitignore
├── .travis.yml
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── demos/
│   ├── Cargo.toml
│   └── src/
│       ├── baz.rs
│       ├── biz.rs
│       └── main.rs
├── metered/
│   ├── Cargo.toml
│   ├── proptest-regressions/
│   │   └── num_wrapper.txt
│   └── src/
│       ├── atomic.rs
│       ├── clear.rs
│       ├── common/
│       │   ├── error_count.rs
│       │   ├── hit_count.rs
│       │   ├── in_flight.rs
│       │   ├── mod.rs
│       │   ├── none_count.rs
│       │   ├── response_time.rs
│       │   └── throughput/
│       │       ├── atomic_tps.rs
│       │       ├── mod.rs
│       │       └── tx_per_sec.rs
│       ├── hdr_histogram.rs
│       ├── int_counter.rs
│       ├── int_gauge.rs
│       ├── lib.rs
│       ├── metric.rs
│       ├── num_wrapper.rs
│       └── time_source.rs
├── metered-macro/
│   ├── Cargo.toml
│   └── src/
│       ├── error_count.rs
│       ├── error_count_opts.rs
│       ├── lib.rs
│       ├── measure_opts.rs
│       ├── metered.rs
│       └── metered_opts.rs
└── rustfmt-unstable.toml

================================================
FILE CONTENTS
================================================

================================================
FILE: .cargo/config
================================================
[alias]
# Run against all targets
check-all = "check --all --all-targets --all-features"
clippy-all = "clippy --all --all-targets --all-features -- -Dwarnings -Drust-2018-idioms -Adeprecated"
# Format Rust code with stable-compatible nightly features
fmt-unstable = "fmt --all -- --config-path rustfmt-unstable.toml"



================================================
FILE: .gitignore
================================================
/target
**/target
**/*.rs.bk
Cargo.lock


================================================
FILE: .travis.yml
================================================
language: rust

cache: cargo

rust:
  - stable
  - beta
  - nightly

matrix:
  allow_failures:
    - rust: nightly
  fast_finish: true

script:
  - cargo build --verbose --all
  - cargo test --verbose --all

notifications:
  email: false
 


================================================
FILE: Cargo.toml
================================================
[workspace]
members = [
  "metered",
  "metered-macro",
]


================================================
FILE: LICENSE-APACHE
================================================
       Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "{}"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright 2018-2019 Simon Chemouil

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

================================================
FILE: LICENSE-MIT
================================================
Copyright (c) 2018-2019 Simon Chemouil

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: README.md
================================================
# metered-rs
[![Build Status](https://travis-ci.org/magnet/metered-rs.svg?branch=master)](https://travis-ci.org/magnet/metered-rs)
[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](
https://github.com/magnet/metered-rs)
[![Cargo](https://img.shields.io/crates/v/metered.svg)](
https://crates.io/crates/metered)
[![Documentation](https://docs.rs/metered/badge.svg)](
https://docs.rs/metered)
[![Rust 1.31+](https://img.shields.io/badge/rust-1.31+-lightgray.svg)](
https://www.rust-lang.org)

## Fast, ergonomic metrics for Rust!

Metered helps you measure the performance of your programs in production. Inspired by Coda Hale's Java metrics library, Metered makes live measurements easy by providing declarative and procedural macros to measure your program without altering your logic.

Metered is built with the following principles in mind:
 * **high ergonomics but no magic**: measuring code should just be a matter of annotating code. Metered lets you build your own metric registries from bare metrics, or will generate one using procedural macros. It does not use shared globals or statics.

 * **constant, very low overhead**: good ergonomics should not come with an overhead; the only overhead is the one imposed by actual metric back-ends themselves (e.g, counters, gauges, histograms), and those provided in Metered do not allocate after initialization.  Metered will generate metric registries as regular Rust `struct`s, so there is no lookup involved with finding a metric. Metered provides both unsynchronized and thread-safe metric back-ends so that single-threaded or share-nothing architectures don't pay for synchronization. Where possible, thread-safe metric back-ends provided by Metered use lock-free data-structures.

 * **extensible**: metrics are just regular types that implement the [`Metric`](https://docs.rs/metered/latest/metered/metric/trait.Metric.html) trait with a specific behavior. Metered's macros let you refer to any Rust type, resulting in user-extensible attributes!

 Many metrics are only meaningful if we get precise statistics. When it comes to low-latency, high-range histograms, there's nothing better than [Gil Tene's High Dynamic Range Histograms](http://hdrhistogram.org/) and Metered uses [the official Rust port](https://github.com/HdrHistogram/HdrHistogram_rust) by default for its histograms.


## Changelog

* 0.9.0:
  * Wrapping int metrics instead of under/overflow
  * Provide methods to increment or decrement int metrics by more than 1, useful for batched computations
  * Add blanket implementations for `Clear` (contributed by [@plankton6](https://github.com/plankton6)) 
  * Add len method to `HdrHistogram` (contributed by [@plankton6](https://github.com/plankton6)) 
  * Code quality fixes and dependency updates
* 0.8.0:
  * Update Metrics via `OnResultMut` rather than an `OnResult` to support metrics that require mutable access to the result - for instance to consume a `Stream` (contributed by [@w4](https://github.com/w4))
* 0.7.0:
  * Expose inner metric backend `Throughput` type (fixes issue #30)
  * Implement `Deref` for all top-level metrics
  * Expose inner metric backend `Throughput` type
  * Add `skip_cleared` option to `error_count` attribute  (contributed by [@w4](https://github.com/w4))
     * Introduce a new `Clearable` trait that exposes behavior for metrics that implement `Clear` (in an effort of backwards compatibility).  Currently only implemented on counters.
     * Default behavior can be controlled by the a build-time feature, `error-count-skip-cleared-by-default`
* 0.6.0:
  * Extend `error_count` macro to allow `nested` enum error variants to be reported, providing zero-cost error tracking for nested errors (contributed by [@w4](https://github.com/w4))
* 0.5.0:
  * Make inner metrics public (contributed by [@nemosupremo](https://github.com/nemosupremo))
  * Provide `error_count` macro to generate a tailored `ErrorCount` metric counting variants for an error enum (contributed by [@w4](https://github.com/w4))
  * Use `Drop` to automatically trigger metrics that don't rely on the result value (affects `InFlight`, `ResponseTime`, `Throughput`)
* 0.4.0:
  * Add allow(missing_docs) to generated structs (This allows to use metered structs in Rust code with lint level warn(missing_docs) or even deny(missing_docs)) (contributed by [@reyk](https://github.com/reyk))
  * Implement `Clear` for generated registries (contributed by [@eliaslevy](https://github.com/eliaslevy))
  * Implement `Histogram` and `Clear` for `RefCell<HdrHistogram>` (contributed by [@eliaslevy](https://github.com/eliaslevy))
  * Introduce an `Instant` with microsecond precision (contributed by [@eliaslevy](https://github.com/eliaslevy))
     * API breaking change: `Instant.elapsed_millis` is renamed to `elapsed_time`, and a new associated constant, `ONE_SEC` is introduced to specify one second in the instant units.
  * Make `AtomicTxPerSec` and `TxPerSec` visible by reexporting  (contributed by [@eliaslevy](https://github.com/eliaslevy))
  * Add `StdInstant` as the default type parameter for `T: Instant` in `TxPerSec`  (contributed by [@eliaslevy](https://github.com/eliaslevy))
  * Modify HdrHistogram to work with serde_prometheus (contributed by [@w4](https://github.com/w4))
     * To be used with [serde_prometheus](https://github.com/w4/serde_prometheus) and any HTTP server.
  * Bumped dependencies:
     * `indexmap`: 1.1 -> 1.3 
     * `hdrhistogram`: 6.3 -> 7.1 
     * `parking_lot`: 0.9 -> 0.10  
* 0.3.0:
  * Fix to preserve span in `async` measured methods.
  * Update nightly sample for new syntax and Tokio 0.2-alpha (using std futures, will need Rust >= 1.39, nightly or not)
  * Updated dependencies to use `syn`, `proc-macro2` and `quote` 1.0
* 0.2.2:
  * Async support in `#measured` methods don't rely on async closures anymore, so client code will not require the `async_closure` feature gate.
  * Updated dependency versions
* 0.2.1:
  * Under certain circumstances, Serde would serialize "nulls" for `PhantomData` markers in `ResponseTime` and `Throughput` metrics. They are now explicitely excluded.
* 0.2.0:
  * Support for `.await` notation users (no more `await!()`)
* 0.1.3:
  * Fix for early returns in `#[measure]`'ed methods
  * Removed usage of crate `AtomicRefCell` which sometimes panicked .
  * Support for custom registry visibility.
  * Support for `async` + `await!()` macro users.


## Using Metered

Metered comes with a variety of useful metrics ready out-of-the-box:
* `HitCount`: a counter tracking how much a piece of code was hit.
* `ErrorCount`: a counter tracking how many errors were returned -- (works on any expression returning a std `Result`)
* `InFlight`: a gauge tracking how many requests are active 
* `ResponseTime`: statistics backed by an HdrHistogram of the duration of an expression
* `Throughput`: statistics backed by an HdrHistogram of how many times an expression is called per second.

These metrics are usually applied to methods, using provided procedural macros that generate the boilerplate.

To achieve higher performance, these stock metrics can be customized to use non-thread safe (`!Sync`/`!Send`) datastructures, but they default to thread-safe datastructures implemented using lock-free strategies where possible. This is an ergonomical choice to provide defaults that work in all situations.

Metered is designed as a zero-overhead abstraction -- in the sense that the higher-level ergonomics should not cost over manually adding metrics. Notably, stock metrics will *not* allocate memory after they're initialized the first time.  However, they are triggered at every method call and it can be interesting to use lighter metrics (e.g `HitCount`) in hot code paths and favour heavier metrics (`Throughput`, `ResponseTime`) in higher-level entry points.

If a metric you need is missing, or if you want to customize a metric (for instance, to track how many times a specific error occurs, or react depending on your return type), it is possible to implement your own metrics simply by implementing the trait `metered::metric::Metric`.

Metered does not use statics or shared global state. Instead, it lets you either build your own metric registry using the metrics you need, or can generate a metric registry for you using method attributes. Metered will generate one registry per `impl` block annotated with the `metered` attribute, under the name provided as the `registry` parameter. By default, Metered will expect the registry to be accessed as `self.metrics` but the expression can be overridden with the `registry_expr` attribute parameter. See the demos for more examples.

Metered will generate metric registries that derive `Debug` and `serde::Serialize` to extract your metrics easily. Metered generates one sub-registry per method annotated with the `measure` attribute, hence organizing metrics hierarchically. This ensures access time to metrics in generated registries is always constant (and, when possible, cache-friendly), without any overhead other than the metric itself.

Metered will happily measure any method, whether it is `async` or not, and the metrics will work as expected (e.g, `ResponseTime` will return the completion time across `await`'ed invocations).

Right now, Metered does not provide bridges to external metric storage or monitoring systems. Such support is planned in separate modules (contributions welcome!).

## Required Rust version

Metered works on `Rust` stable, starting 1.31.0.

It does not use any nightly features. There may be a `nightly` feature flag at some point to use upcoming Rust features (such as `const fn`s), and similar features from crates Metered depends on, but this is low priority (contributions welcome).

## Example using procedural macros (recommended)

```rust
use metered::{metered, Throughput, HitCount};

#[derive(Default, Debug, serde::Serialize)]
pub struct Biz {
    metrics: BizMetrics,
}

#[metered(registry = BizMetrics)]
impl Biz {
    #[measure([HitCount, Throughput])]
    pub fn biz(&self) {        
        let delay = std::time::Duration::from_millis(rand::random::<u64>() % 200);
        std::thread::sleep(delay);
    }   
}
```

In the snippet above, we will measure the `HitCount` and `Throughput` of the `biz` method.

This works by first annotating the `impl` block with the `metered` annotation and specifying the name Metered should give to the metric registry (here `BizMetrics`). Later, Metered will assume the expression to access that repository is `self.metrics`, hence we need a `metrics` field with the `BizMetrics` type in `Biz`. It would be possible to use another field name by specificying another registry expression, such as `#[metered(registry = BizMetrics, registry_expr = self.my_custom_metrics)]`.

Then, we must annotate which methods we wish to measure using the `measure` attribute, specifying the metrics we wish to apply: the metrics here are simply types of structures implementing the `Metric` trait, and you can define your own. Since there is no magic, we must ensure `self.metrics` can be accessed, and this will only work on methods with a `&self` or `&mut self` receiver.

Let's look at `biz`'s code a second: it's a blocking method that returns after between 0 and 200ms, using `rand::random`. Since `random` has a random distribution, we can expect the mean sleep time to be around 100ms. That would mean around 10 calls per second per thread.

In the following test, we spawn 5 threads that each will call `biz()` 200 times. We thus can expect a hit count of 1000, that it will take around 20 seconds (which means 20 samples, since we collect one sample per second), and around 50 calls per second (10 per thread, with 5 threads).

```rust
use std::thread;
use std::sync::Arc;

fn test_biz() {
    let biz = Arc::new(Biz::default());
    let mut threads = Vec::new();
    for _ in 0..5 {
        let biz = Arc::clone(&biz);
        let t = thread::spawn(move || {
            for _ in 0..200 {
                biz.biz();
            }
        });
        threads.push(t);
    }
    for t in threads {
        t.join().unwrap();
    }
    // Print the results!
    let serialized = serde_yaml::to_string(&*biz).unwrap();
    println!("{}", serialized);
}
```

We can then use serde to serialize our type as YAML:
```yaml
metrics:
  biz:
    hit_count: 1000
    throughput:
      - samples: 20
        min: 35
        max: 58
        mean: 49.75
        stdev: 5.146600819958742
        90%ile: 55
        95%ile: 55
        99%ile: 58
        99.9%ile: 58
        99.99%ile: 58
      - ~
```

We see we indead have a mean of 49.75 calls per second, which corresponds to our expectations.

The Hdr Histogram backing these statistics is able to give much more than fixed percentiles, but this is a practical view when using text. For a better performance analysis, please watch Gil Tene's talks ;-).

## Macro Reference

### The `metered` attribute

`#[metered(registry = YourRegistryName, registry_expr = self.wrapper.my_registry)]` 

`registry` is mandatory and must be a valid Rust ident.

`registry_expr` defaults to `self.metrics`, alternate values must be a valid Rust expression. This setting lets you configure the expression which resolves to the registry. Please note that this triggers an immutable borrow of that expression.

`visibility` defaults to `pub(crate)`, and must be a valid struct Rust visibility (e.g, `pub`, `<nothing>`, `pub(self)`, etc). This setting lets you alter the visibility of the generated registry `struct`s. The registry fields are always public and named after snake cased methods or metrics.

### The `measure` attribute

Single metric:

`#[measure(path::to::MyMetric<u64>)]`

or: 

`#[measure(type = path::to::MyMetric<u64>)]`

Multiple metrics:

`#[measure([path::to::MyMetric<u64>, path::AnotherMetric])]`

or

`#[measure(type = [path::to::MyMetric<u64>, path::AnotherMetric])]`

The `type` keyword is allowed because other keywords are planned for future extra attributes (e.g, instantation options).

When `measure` attribute is applied to an `impl` block, it applies for every method that has a `measure` attribute. If a method does not need extra measure infos, it is possible to annotate it with simply `#[measure]` and the `impl` block's `measure` configuration will be applied.

The `measure` keyword can be added several times on an `impl` block or method, which will add to the list of metrics applied. Adding the same metric several time will lead in a name clash.

### Design

Metered's custom attribute parsing supports using reserved keywords and arbitrary Rust syntax. The code has been extracted to the [Synattra](https://github.com/magnet/synattra) project, which provides useful methods on top of the Syn parser for Attribute parsing.

Metered's metrics can wrap any piece of code, regardless of whether they're `async` blocks or not, using hygienic macros to emulate an approach similar to aspect-oriented programming. That code has been extracted to the [Aspect-rs](https://github.com/magnet/aspect-rs) project!


## License

Licensed under either of

 * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
 * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)

at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the Apache-2.0
license, shall be dual licensed as above, without any additional terms or
conditions.


================================================
FILE: demos/Cargo.toml
================================================
[package]
name = "metered-demo"
version = "0.1.0"
authors = ["Simon Chemouil <simon.chemouil@lambdacube.fr>"]
edition = "2018"

#break out of workspace
[workspace]

[dependencies]
hdrhistogram = "7.5"
rand = "0.8"
atomic = "0.5"
tokio = { version = "1.19", features = [ "rt", "rt-multi-thread", "time" ] }
serde = { version = "1.0", features = ["derive"] }
serde_prometheus = "0.1"
thiserror = "1.0"

[dependencies.metered]
version = "0.9"
path = "../metered"
features = [
    # Enable to override the default and skip "cleared" entries from the `error_count`
    # even when the attribute is not specified.
    "error-count-skip-cleared-by-default"
    ]


================================================
FILE: demos/src/baz.rs
================================================
#![allow(dead_code)]

use metered::{metered, ErrorCount, HitCount, InFlight, ResponseTime};
use thiserror::Error;

#[metered::error_count(name = LibErrorCount, visibility = pub)]
#[derive(Debug, Error)]
pub enum LibError {
    #[error("I failed!")]
    Failure,
    #[error("Bad input")]
    BadInput,
}

#[metered::error_count(name = BazErrorCount, visibility = pub, skip_cleared = true)]
#[derive(Debug, Error)]
pub enum BazError {
    #[error("lib error: {0}")]
    Lib(#[from] #[nested] LibError),
    #[error("io error")]
    Io,
}

#[derive(Default, Debug, serde::Serialize)]
pub struct Baz {
    metric_reg: BazMetricRegistry,
}

#[metered(registry = BazMetricRegistry, /* default = self.metrics */ registry_expr = self.metric_reg, visibility = pub(self))]
#[measure(InFlight)] // Applies to all methods that have the `measure` attribute
impl Baz {
    // This is measured with an InFlight gauge, because it's the default on the block.
    #[measure]
    pub fn bir(&self) {
        println!("bir");
        let delay = std::time::Duration::from_millis(rand::random::<u64>() % 2000);
        std::thread::sleep(delay);
    }

    // This is not measured
    pub fn bor(&self) {
        println!("bor");
    }

    #[measure(ResponseTime)]
    pub fn foo(&self) {
        println!("foo !");
        let delay = std::time::Duration::from_millis(rand::random::<u64>() % 2000);
        std::thread::sleep(delay);
    }

    #[measure(type = HitCount<metered::atomic::AtomicInt<u64>>)]
    #[measure(ErrorCount)]
    #[measure(ResponseTime)]
    pub fn bar(&self, should_fail: bool) -> Result<(), &'static str> {
        if !should_fail {
            println!("bar !");
            Ok(())
        } else {
            Err("I failed!")
        }
    }
    #[measure([ErrorCount, ResponseTime])]
    pub async fn baz(&self, should_fail: bool) -> Result<(), &'static str> {
        let delay = std::time::Duration::from_millis(rand::random::<u64>() % 2000);
        tokio::time::sleep(delay).await;
        if !should_fail {
            println!("baz !");
            Ok(())
        } else {
            Err("I failed!")
        }
    }

    #[measure([ResponseTime])]
    pub fn bazium(
        &self,
        should_fail: bool,
    ) -> impl std::future::Future<Output = Result<(), &'static str>> {
        async move {
            let delay = std::time::Duration::from_millis(rand::random::<u64>() % 2000);
            tokio::time::sleep(delay).await;
            if !should_fail {
                println!("baz !");
                Ok(())
            } else {
                Err("I failed!")
            }
        }
    }

    #[measure([HitCount, BazErrorCount])]
    pub async fn bazle(&self, should_fail: bool) -> Result<(), BazError> {
        if !should_fail {
            println!("bazle !");
            Ok(())
        } else {
            Err(LibError::Failure.into())
        }
    }

    #[measure]
    pub unsafe fn bad(&self, v: &[u8]) {
        let _ = std::str::from_utf8_unchecked(v);
    }

    // This is not measured either
    pub fn bur() {
        println!("bur");
    }
}


================================================
FILE: demos/src/biz.rs
================================================
use metered::{metered, HitCount, Throughput};

#[derive(Default, Debug, serde::Serialize)]
pub struct Biz {
    pub(crate) metrics: BizMetrics,
}

#[metered(registry = BizMetrics)]
#[measure([HitCount, Throughput])]
impl Biz {
    // This is measured with an Throughput metric (TPS)
    #[measure]
    pub fn biz(&self) {
        let delay = std::time::Duration::from_millis(rand::random::<u64>() % 200);
        std::thread::sleep(delay);
    }
}


================================================
FILE: demos/src/main.rs
================================================
use metered::clear::Clear;
use metered::*;
mod baz;
use baz::Baz;
mod biz;
use biz::Biz;
use std::collections::HashMap;

#[derive(Default, Debug, serde::Serialize)]
struct TestMetrics {
    hit_count: HitCount,
    error_count: ErrorCount,
}

fn test(should_fail: bool, metrics: &TestMetrics) -> Result<(), ()> {
    let hit_count = &metrics.hit_count;
    let error_count = &metrics.error_count;
    measure!(hit_count, {
        measure!(error_count, {
            println!("test !");
            if should_fail {
                Err(())
            } else {
                Ok(())
            }
        })
    })
}

fn test_incr(metrics: &TestMetrics) -> Result<(), ()> {
    let hit_count = &metrics.hit_count;
    hit_count.incr_by(3);
    Ok(())
}

fn sync_procmacro_demo(baz: &Baz) {
    for i in 1..=10 {
        baz.foo();
        let _ = baz.bar(i % 3 == 0);
    }
}

async fn async_procmacro_demo(baz: Baz) {
    for i in 1..=5 {
        let _ = baz.baz(i % 3 == 0).await;
        let _ = baz.bazle(i % 3 == 0).await;
    }

    // Print the results!
    let serialized = serde_prometheus::to_string(&baz, None, HashMap::new()).unwrap();
    println!("{}", serialized);
}

fn simple_api_demo() {
    let metrics = TestMetrics::default();

    let _ = test(false, &metrics);
    let _ = test(true, &metrics);
    let _ = test_incr(&metrics);

    // Print the results!
    let serialized = serde_prometheus::to_string(&metrics, None, HashMap::new()).unwrap();
    println!("{}", serialized);
}

use std::sync::Arc;
use std::thread;

fn test_biz() {
    println!("Running Biz throughput demo...(will take 20 seconds)");
    let biz = Arc::new(Biz::default());
    do_test_biz(&biz);
    println!("Clearing Biz metrics and running throughput demo again...(will take 20 seconds)");
    biz.metrics.clear();
    do_test_biz(&biz);
}

fn do_test_biz(biz: &Arc<Biz>) {
    let mut threads = Vec::new();
    for _ in 0..5 {
        let biz = Arc::clone(&biz);
        let t = thread::spawn(move || {
            for _ in 0..200 {
                biz.biz();
            }
        });
        threads.push(t);
    }
    for t in threads {
        t.join().unwrap();
    }
    println!("Running Biz throughput demo... done! Here are the metrics for that run:");
    // Print the results!
    let serialized = serde_prometheus::to_string(&**biz, None, HashMap::new()).unwrap();
    println!("{}", serialized);
}

fn main() {
    simple_api_demo();

    test_biz();

    let baz = Baz::default();

    sync_procmacro_demo(&baz);
    let rt = tokio::runtime::Runtime::new().unwrap();
    rt.block_on(async_procmacro_demo(baz));
}


================================================
FILE: metered/Cargo.toml
================================================
[package]
name = "metered"
version = "0.9.0"
authors = ["Simon Chemouil <simon.chemouil@lambdacube.fr>"]
license = "Apache-2.0 OR MIT"
readme = "../README.md"
keywords = ["metrics", "macro"]
repository = "https://github.com/magnet/metered-rs"
description = """
Fast, ergonomic metrics for Rust!
"""
categories = ["rust-patterns", "development-tools::profiling", "data-structures", "algorithms", "asynchronous"]
edition = "2018"

[dependencies]
metered-macro = { version = "0.9.0", path = "../metered-macro" }
aspect = "0.3"
hdrhistogram = "7.5"
atomic = "0.5"
parking_lot = "0.12"
serde = { version = "1.0", features = ["derive"] }
cfg-if = "1.0.0"

[dev-dependencies]
rand = "0.8"
proptest = "1.0"

[features]
# no features by default
default = []

# Use the serde feature to make metered' types implement Serialize
serialize = []

# When enabled, the error count macro will skip serializing cleared entries (e.g counters with value 0)
# This can be overridden with the `skip_cleared` macro attribute
error-count-skip-cleared-by-default = ["metered-macro/error-count-skip-cleared-by-default"]



================================================
FILE: metered/proptest-regressions/num_wrapper.txt
================================================
# Seeds for failure cases proptest has generated in the past. It is
# automatically read and these particular cases re-run before any
# novel cases are generated.
#
# It is recommended to check this file in to source control so that
# everyone who runs the test benefits from these saved cases.
cc 8a90d39ed68bfe0be7ac677e9dde1d980a2ea3208a402db987e3c6ae79187527 # shrinks to x = 0, y = 0


================================================
FILE: metered/src/atomic.rs
================================================
//! A module providing new-type Atomic wrapper that implements Debug &
//! Serialize.

use serde::{Serialize, Serializer};
use std::{
    fmt,
    fmt::{Debug, Display},
    sync::atomic::Ordering,
};

/// A new-type wrapper over `atomic::Atomic` that supports serde serialization
/// and a cleaner debug output.
///
/// All default operations on the wrapper type are using a relaxed memory
/// ordering, which makes it suitable for counters and little else.
#[derive(Default)]
pub struct AtomicInt<T: Copy> {
    /// The inner atomic instance
    pub inner: atomic::Atomic<T>,
}

impl<T: Copy> AtomicInt<T> {
    /// Returns the current value
    pub fn get(&self) -> T {
        self.inner.load(Ordering::Relaxed)
    }
}

impl<T: Copy + Display> Debug for AtomicInt<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.get())
    }
}

macro_rules! impl_blocks_for {
    ($int:path: $method_name:ident) => {
        impl AtomicInt<$int> {
            /// Increments self
            ///
            /// Returns the previous count
            pub fn incr(&self) -> $int {
                self.inner.fetch_add(1, Ordering::Relaxed)
            }

            /// Increments self by count
            ///
            /// Returns the previous count
            pub fn incr_by(&self, count: $int) -> $int {
                self.inner.fetch_add(count, Ordering::Relaxed)
            }

            /// Decrements self
            ///
            /// Returns the previous count
            pub fn decr(&self) -> $int {
                self.inner.fetch_sub(1, Ordering::Relaxed)
            }

            /// Decrements self by count
            ///
            /// Returns the previous count
            pub fn decr_by(&self, count: $int) -> $int {
                self.inner.fetch_sub(count, Ordering::Relaxed)
            }

            /// Sets self to a new value
            pub fn set(&self, v: $int) {
                self.inner.store(v, Ordering::Relaxed);
            }
        }

        impl Serialize for AtomicInt<$int> {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where
                S: Serializer,
            {
                serializer.$method_name(self.get())
            }
        }
    };
}

impl_blocks_for!(u8: serialize_u8);
impl_blocks_for!(u16: serialize_u16);
impl_blocks_for!(u32: serialize_u32);
impl_blocks_for!(u64: serialize_u64);
impl_blocks_for!(u128: serialize_u128);

#[cfg(test)]
mod tests {
    // The `atomic` crate makes no explicit guarantees on wrapping on overflow
    // however `std` atomics that it uses underneath do.
    //
    // This test ensures `atomic`'s behavior does not deviate.
    #[test]
    fn test_atomic_wraps() {
        use super::*;
        let a = AtomicInt {
            inner: atomic::Atomic::<u8>::new(255u8),
        };

        a.incr();
        assert_eq!(a.get(), 0u8);

        a.decr();
        assert_eq!(a.get(), 255u8);
    }
}


================================================
FILE: metered/src/clear.rs
================================================
//! A module providing a Clear trait which signals metrics to clear their state
//! if applicable.

use std::sync::Arc;

/// The `Clear` trait is used to signal metrics to clear their state if
/// applicable
///
/// While it is recommended all metrics should implement `Clear`, for instance
/// to derive `Clear` on registries, some metrics may choose to do nothing. For
/// instance, Gauges would be left in an inconsistent state if they were altered
/// during clear.
pub trait Clear {
    /// Requests to clear self.
    fn clear(&self);
}

impl<T: Clear> Clear for Arc<T> {
    fn clear(&self) {
        (**self).clear();
    }
}

impl<T: Clear> Clear for &T {
    fn clear(&self) {
        (*self).clear();
    }
}

/// The `Clearable` trait is used to provide metadata around some types that can
/// be cleared.
pub trait Clearable {
    /// Returns true if self has been cleared and not yet been written to since.
    fn is_cleared(&self) -> bool;
}


================================================
FILE: metered/src/common/error_count.rs
================================================
//! A module providing the `ErrorCount` metric.

use crate::{
    atomic::AtomicInt,
    clear::Clear,
    metric::{Counter, Metric},
};
use aspect::{Advice, Enter, OnResult};
use serde::Serialize;
use std::ops::Deref;

/// A metric counting how many times an expression typed std `Result` as
/// returned an `Err` variant.
///
/// This is a light-weight metric.
///
/// By default, `ErrorCount` uses a lock-free `u64` `Counter`, which makes sense
/// in multithread scenarios. Non-threaded applications can gain performance by
/// using a `std::cell:Cell<u64>` instead.
#[derive(Clone, Default, Debug, Serialize)]
pub struct ErrorCount<C: Counter = AtomicInt<u64>>(pub C);

impl<C: Counter, T, E> Metric<Result<T, E>> for ErrorCount<C> {}

impl<C: Counter> Enter for ErrorCount<C> {
    type E = ();
    fn enter(&self) {}
}

impl<C: Counter, T, E> OnResult<Result<T, E>> for ErrorCount<C> {
    fn on_result(&self, _: (), r: &Result<T, E>) -> Advice {
        if r.is_err() {
            self.0.incr();
        }
        Advice::Return
    }
}

impl<C: Counter> Clear for ErrorCount<C> {
    fn clear(&self) {
        self.0.clear()
    }
}

impl<C: Counter> Deref for ErrorCount<C> {
    type Target = C;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}


================================================
FILE: metered/src/common/hit_count.rs
================================================
//! A module providing the `HitCount` metric.

use crate::{
    atomic::AtomicInt,
    clear::Clear,
    metric::{Counter, Metric},
};
use aspect::{Enter, OnResult};
use serde::Serialize;
use std::ops::Deref;

/// A metric counting how many times an expression as been hit, before it
/// returns.
///
/// This is a light-weight metric.
///
/// By default, `HitCount` uses a lock-free `u64` `Counter`, which makes sense
/// in multithread scenarios. Non-threaded applications can gain performance by
/// using a `std::cell:Cell<u64>` instead.
#[derive(Clone, Default, Debug, Serialize)]
pub struct HitCount<C: Counter = AtomicInt<u64>>(pub C);

impl<C: Counter, R> Metric<R> for HitCount<C> {}

impl<C: Counter> Enter for HitCount<C> {
    type E = ();
    fn enter(&self) -> Self::E {
        self.0.incr();
    }
}

impl<C: Counter, R> OnResult<R> for HitCount<C> {}

impl<C: Counter> Clear for HitCount<C> {
    fn clear(&self) {
        self.0.clear()
    }
}

impl<C: Counter> Deref for HitCount<C> {
    type Target = C;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}


================================================
FILE: metered/src/common/in_flight.rs
================================================
//! A module providing the `InFlight` metric.

use crate::{
    atomic::AtomicInt,
    clear::Clear,
    metric::{Gauge, Metric},
};
use aspect::{Advice, Enter, OnResult};
use serde::Serialize;
use std::ops::Deref;

/// A metric providing an in-flight gauge, showing how many calls are currently
/// active for an expression.
///
/// This is a light-weight metric.
///
/// This makes sense mostly in a multi-threaded situation where several threads
/// may call the same method constantly, and we want to monitor how many are
/// active at a given time.
///
/// The [`Throughput`] metric shows an alternative view
/// of the same picture, by reporting how many transactions per seconds are
/// processed by an expression.
///
/// By default, `InFlight` uses a lock-free `u64` [`Gauge`], which makes sense
/// in multithread scenarios. Non-threaded applications can gain performance by
/// using a `std::cell:Cell<u64>` instead.

#[derive(Clone, Default, Debug, Serialize)]
pub struct InFlight<G: Gauge = AtomicInt<u64>>(pub G);

impl<G: Gauge, R> Metric<R> for InFlight<G> {}

impl<G: Gauge> Enter for InFlight<G> {
    type E = ();
    fn enter(&self) {
        self.0.incr();
    }
}

impl<G: Gauge, R> OnResult<R> for InFlight<G> {
    fn leave_scope(&self, _: ()) -> Advice {
        self.0.decr();
        Advice::Return
    }
}

impl<G: Gauge> Clear for InFlight<G> {
    fn clear(&self) {
        // Do nothing: an InFlight metric
        // would get in an inconsistent state if cleared
    }
}

impl<G: Gauge> Deref for InFlight<G> {
    type Target = G;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}


================================================
FILE: metered/src/common/mod.rs
================================================
//! A module providing common metrics.

mod error_count;
mod hit_count;
mod in_flight;
mod none_count;
mod response_time;
mod throughput;

pub use error_count::ErrorCount;
pub use hit_count::HitCount;
pub use in_flight::InFlight;
pub use none_count::NoneCount;
pub use response_time::ResponseTime;
pub use throughput::{AtomicTxPerSec, RecordThroughput, Throughput, TxPerSec};


================================================
FILE: metered/src/common/none_count.rs
================================================
//! A module providing the `NoneCount` metric.

use crate::{
    atomic::AtomicInt,
    clear::Clear,
    metric::{Counter, Metric},
};
use aspect::{Advice, Enter, OnResult};
use serde::Serialize;
use std::ops::Deref;

/// A metric counting how many times the return value is Ok(None) or None.
///
/// `SomeCount` is not provided since can be calculated by subtracting `NoneCount` from `HitCount`.
///
/// This is a light-weight metric.
///
/// By default, `NoneCount` uses a lock-free `u64` `Counter`, which makes sense
/// in multithread scenarios. Non-threaded applications can gain performance by
/// using a `std::cell:Cell<u64>` instead.
#[derive(Clone, Default, Debug, Serialize)]
pub struct NoneCount<C: Counter = AtomicInt<u64>>(pub C);

impl<C: Counter, T, E> Metric<Result<Option<T>, E>> for NoneCount<C> {}

impl<C: Counter, T> Metric<Option<T>> for NoneCount<C> {}

impl<C: Counter> Enter for NoneCount<C> {
    type E = ();
    fn enter(&self) {}
}

impl<C: Counter, T, E> OnResult<Result<Option<T>, E>> for NoneCount<C> {
    fn on_result(&self, _: (), r: &Result<Option<T>, E>) -> Advice {
        if matches!(r, Ok(None)) {
            self.0.incr();
        }
        Advice::Return
    }
}

impl<C: Counter, T> OnResult<Option<T>> for NoneCount<C> {
    fn on_result(&self, _: (), r: &Option<T>) -> Advice {
        if r.is_none() {
            self.0.incr();
        }
        Advice::Return
    }
}

impl<C: Counter> Clear for NoneCount<C> {
    fn clear(&self) {
        self.0.clear();
    }
}

impl<C: Counter> Deref for NoneCount<C> {
    type Target = C;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}


================================================
FILE: metered/src/common/response_time.rs
================================================
//! A module providing the `ResponseTime` metric.

use crate::{
    clear::Clear,
    hdr_histogram::AtomicHdrHistogram,
    metric::{Histogram, Metric},
    time_source::{Instant, StdInstant},
};
use aspect::{Advice, Enter, OnResult};
use serde::{Serialize, Serializer};
use std::{ops::Deref, time::Duration};

/// A metric measuring the response time of an expression, that is the duration
/// the expression needed to complete.
///
/// Because it retrieves the current time before calling the expression,
/// computes the elapsed duration and registers it to an histogram, this is a
/// rather heavy-weight metric better applied at entry-points.
///
/// By default, `ResponseTime` uses an atomic hdr histogram and a synchronized
/// time source, which work better in multithread scenarios. Non-threaded
/// applications can gain performance by using unsynchronized structures
/// instead.
#[derive(Clone)]
pub struct ResponseTime<H: Histogram = AtomicHdrHistogram, T: Instant = StdInstant>(
    pub H,
    std::marker::PhantomData<T>,
);

impl<H: Histogram, T: Instant> ResponseTime<H, T> {
    /// Build a ResponseTime with a custom histogram bound
    /// 
    /// ```rust
    /// use std::time::Duration;
    /// use metered::{ResponseTime, hdr_histogram::AtomicHdrHistogram, time_source::StdInstantMicros};
    /// 
    /// let response_time_millis: ResponseTime =
    ///     ResponseTime::with_bound(Duration::from_secs(4));
    /// 
    /// assert_eq!(response_time_millis.histogram().bound(), 4_000);
    /// 
    /// let response_time_micros: ResponseTime<AtomicHdrHistogram, StdInstantMicros> =
    ///     ResponseTime::with_bound(Duration::from_secs(4));
    /// 
    /// assert_eq!(response_time_micros.histogram().bound(), 4_000_000);
    /// ```
    pub fn with_bound(bound: Duration) -> Self {
        ResponseTime(H::with_bound(T::units(bound)), std::marker::PhantomData)
    }
}

impl<H: Histogram, T: Instant> Default for ResponseTime<H, T> {
    fn default() -> Self {
        // A HdrHistogram measuring latencies from 1ms to 5minutes
        // All recordings will be saturating, that is, a value higher than 5 minutes
        // will be replace by 5 minutes...
        ResponseTime(H::with_bound(5 * 60 * T::ONE_SEC), std::marker::PhantomData)
    }
}

impl<H: Histogram, T: Instant, R> Metric<R> for ResponseTime<H, T> {}

impl<H: Histogram, T: Instant> Enter for ResponseTime<H, T> {
    type E = T;

    fn enter(&self) -> T {
        T::now()
    }
}

impl<H: Histogram, T: Instant, R> OnResult<R> for ResponseTime<H, T> {
    fn leave_scope(&self, enter: T) -> Advice {
        let elapsed = enter.elapsed_time();
        self.0.record(elapsed);
        Advice::Return
    }
}

impl<H: Histogram, T: Instant> Clear for ResponseTime<H, T> {
    fn clear(&self) {
        self.0.clear();
    }
}

impl<H: Histogram + Serialize, T: Instant> Serialize for ResponseTime<H, T> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        Serialize::serialize(&self.0, serializer)
    }
}

use std::{fmt, fmt::Debug};
impl<H: Histogram + Debug, T: Instant> Debug for ResponseTime<H, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", &self.0)
    }
}

impl<H: Histogram, T: Instant> Deref for ResponseTime<H, T> {
    type Target = H;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}


================================================
FILE: metered/src/common/throughput/atomic_tps.rs
================================================
use super::{tx_per_sec::TxPerSec, RecordThroughput};
use crate::{
    clear::Clear,
    hdr_histogram::HdrHistogram,
    time_source::{Instant, StdInstant},
};
use parking_lot::Mutex;
use serde::{Serialize, Serializer};

/// Thread-safe implementation of [`super::RecordThroughput`]. It uses a `Mutex`
/// to wrap `TxPerSec`.
pub struct AtomicTxPerSec<T: Instant = StdInstant> {
    /// The inner mutex protecting the `TxPerSec` value holding the histogram
    pub inner: Mutex<TxPerSec<T>>,
}

impl<T: Instant> AtomicTxPerSec<T> {
    /// Returns a cloned snapshot of the inner histogram.
    pub fn histogram(&self) -> HdrHistogram {
        self.inner.lock().hdr_histogram.clone()
    }
}

impl<T: Instant> RecordThroughput for AtomicTxPerSec<T> {
    #[inline]
    fn on_result(&self) {
        self.inner.lock().on_result()
    }
}

impl<T: Instant> Default for AtomicTxPerSec<T> {
    fn default() -> Self {
        AtomicTxPerSec {
            inner: Mutex::new(TxPerSec::default()),
        }
    }
}

impl<T: Instant> Clear for AtomicTxPerSec<T> {
    fn clear(&self) {
        self.inner.lock().clear();
    }
}

impl<T: Instant> Serialize for AtomicTxPerSec<T> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let inner = self.inner.lock();
        Serialize::serialize(&*inner, serializer)
    }
}

use std::{fmt, fmt::Debug};
impl<T: Instant> Debug for AtomicTxPerSec<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let inner = self.inner.lock();
        write!(f, "{:?}", &*inner)
    }
}


================================================
FILE: metered/src/common/throughput/mod.rs
================================================
//! A module providing the `Throughput` metric.

use crate::{
    clear::Clear,
    metric::Metric,
    time_source::{Instant, StdInstant},
};
use aspect::{Advice, Enter, OnResult};
use serde::{Serialize, Serializer};
use std::ops::Deref;

mod atomic_tps;
mod tx_per_sec;

pub use atomic_tps::AtomicTxPerSec;
pub use tx_per_sec::TxPerSec;

/// A metric providing a transaction per second count backed by a histogram.
///
/// Because it retrieves the current time before calling the expression, stores
/// it to appropriately build time windows of 1 second and registers results to
/// a histogram, this is a rather heavy-weight metric better applied at
/// entry-points.
///
/// By default, `Throughput` uses an atomic transaction count backend and a
/// synchronized time source, which work better in multithread scenarios.
/// Non-threaded applications can gain performance by using unsynchronized
/// structures instead.
#[derive(Clone)]
pub struct Throughput<T: Instant = StdInstant, P: RecordThroughput = AtomicTxPerSec<T>>(
    pub P,
    std::marker::PhantomData<T>,
);

/// Trait to record the throughput on a [`Throughput`] instance.
pub trait RecordThroughput: Default {
    /// Called after the execution that the throughput metric is measuring.
    fn on_result(&self);
}

impl<P: RecordThroughput, T: Instant> Default for Throughput<T, P> {
    fn default() -> Self {
        Throughput(P::default(), std::marker::PhantomData)
    }
}

impl<P: RecordThroughput + Serialize + Clear, T: Instant, R> Metric<R> for Throughput<T, P> {}

impl<P: RecordThroughput, T: Instant> Enter for Throughput<T, P> {
    type E = ();

    fn enter(&self) {}
}

impl<P: RecordThroughput + Clear, T: Instant> Clear for Throughput<T, P> {
    fn clear(&self) {
        self.0.clear();
    }
}

impl<P: RecordThroughput + Serialize, T: Instant, R> OnResult<R> for Throughput<T, P> {
    fn leave_scope(&self, _enter: ()) -> Advice {
        self.0.on_result();
        Advice::Return
    }
}

impl<P: RecordThroughput + Serialize, T: Instant> Serialize for Throughput<T, P> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        Serialize::serialize(&self.0, serializer)
    }
}

use std::{fmt, fmt::Debug};
impl<P: RecordThroughput + Debug, T: Instant> Debug for Throughput<T, P> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", &self.0)
    }
}

impl<P: RecordThroughput, T: Instant> Deref for Throughput<T, P> {
    type Target = P;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}


================================================
FILE: metered/src/common/throughput/tx_per_sec.rs
================================================
use super::RecordThroughput;
use crate::{
    clear::Clear,
    hdr_histogram::HdrHistogram,
    time_source::{Instant, StdInstant},
};
use serde::{Serialize, Serializer};

/// Non-thread safe implementation of `RecordThroughput`. Use as
/// `RefCell<TxPerSec<T>>`.
pub struct TxPerSec<T: Instant = StdInstant> {
    /// The inner histogram
    pub hdr_histogram: HdrHistogram,
    start_time: Option<T>,
    last_window: u64,
    count: u64,
    time_source: std::marker::PhantomData<T>,
}

impl<T: Instant> Default for TxPerSec<T> {
    fn default() -> Self {
        TxPerSec {
            // Bound at 100K TPS, higher values will be saturated...
            // TODO: make this configurable :)
            hdr_histogram: HdrHistogram::with_bound(100_000),
            start_time: None,
            last_window: 0,
            count: 0,
            time_source: std::marker::PhantomData,
        }
    }
}

impl<T: Instant> RecordThroughput for std::cell::RefCell<TxPerSec<T>> {
    #[inline]
    fn on_result(&self) {
        self.borrow_mut().on_result()
    }
}

impl<T: Instant> Clear for std::cell::RefCell<TxPerSec<T>> {
    fn clear(&self) {
        self.borrow_mut().clear();
    }
}

impl<T: Instant> TxPerSec<T> {
    /// Record previous count if the 1-sec window has closed and advance time window
    fn update(&mut self) {
        if let Some(ref start_time) = self.start_time {
            let elapsed = start_time.elapsed_time();
            let this_window = elapsed / T::ONE_SEC;
            if this_window > self.last_window {
                // Record this window
                self.hdr_histogram.record(self.count);
                self.count = 0;

                // Record windows with no samples
                let empty_windows = this_window - self.last_window - 1;
                if empty_windows > 0 {
                    self.hdr_histogram.record_n(0, empty_windows)
                }

                // Advance window
                self.last_window = this_window;
            }
        } else {
            // Set first window start time
            self.start_time = Some(T::now());
        };
    }
    pub(crate) fn on_result(&mut self) {
        self.update();
        self.count += 1;
    }

    pub(crate) fn clear(&mut self) {
        self.hdr_histogram.clear();
        self.start_time = None;
        self.last_window = 0;
        self.count = 0;
    }
}

impl<T: Instant> Serialize for TxPerSec<T> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        Serialize::serialize(&self.hdr_histogram, serializer)
    }
}

use std::{fmt, fmt::Debug};
impl<T: Instant> Debug for TxPerSec<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", &self.hdr_histogram)
    }
}


================================================
FILE: metered/src/hdr_histogram.rs
================================================
//! A module providing thread-safe and unsynchronized implementations for
//! Histograms, based on HdrHistogram.

use crate::{clear::Clear, metric::Histogram};
use parking_lot::Mutex;
use serde::{Serialize, Serializer};

/// A thread-safe implementation of HdrHistogram
pub struct AtomicHdrHistogram {
    inner: Mutex<HdrHistogram>,
}

impl AtomicHdrHistogram {
    /// Returns a cloned snapshot of the inner histogram.
    pub fn histogram(&self) -> HdrHistogram {
        self.inner.lock().clone()
    }
}

impl Histogram for AtomicHdrHistogram {
    fn with_bound(max_bound: u64) -> Self {
        let histo = HdrHistogram::with_bound(max_bound);
        let inner = Mutex::new(histo);
        AtomicHdrHistogram { inner }
    }

    fn record(&self, value: u64) {
        self.inner.lock().record(value);
    }
}

impl Clear for AtomicHdrHistogram {
    fn clear(&self) {
        self.inner.lock().clear();
    }
}

impl Serialize for AtomicHdrHistogram {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        use std::ops::Deref;
        let inner = self.inner.lock();
        let inner = inner.deref();
        Serialize::serialize(inner, serializer)
    }
}

use std::{fmt, fmt::Debug};
impl Debug for AtomicHdrHistogram {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let histo = self.inner.lock();
        write!(f, "AtomicHdrHistogram {{ {:?} }}", &*histo)
    }
}

/// An High-Dynamic Range Histogram
///
/// HdrHistograms can record and analyze sampled data in low-latency applications. Read more about HDR Histograms on [http://hdrhistogram.org/](http://hdrhistogram.org/)
///
/// This structure uses the `hdrhistogram` crate under the hood.
#[derive(Clone)]
pub struct HdrHistogram {
    histo: hdrhistogram::Histogram<u64>,
}

impl HdrHistogram {
    /// Instantiates a new HdrHistogram with a max_bound
    ///
    /// For instance, a max_bound of 60 * 60 * 1000 will allow to record
    /// durations varying from 1 millisecond to 1 hour.
    pub fn with_bound(max_bound: u64) -> Self {
        let histo = hdrhistogram::Histogram::<u64>::new_with_bounds(1, max_bound, 2)
            .expect("Could not instantiate HdrHistogram");

        HdrHistogram { histo }
    }

    /// Get the histogram bound
    pub fn bound(&self) -> u64 {
        self.histo.high()
    }

    /// Records a value to the histogram
    ///
    /// This is a saturating record: if the value is higher than `max_bound`,
    /// max_bound will be recorded instead.
    pub fn record(&mut self, value: u64) {
        // All recordings will be saturating
        self.histo.saturating_record(value);
    }

    /// Records  multiple samples for a value to the histogram
    ///
    /// This is a saturating record: if the value is higher than `max_bound`,
    /// max_bound will be recorded instead.
    pub fn record_n(&mut self, value: u64, count: u64) {
        // All recordings will be saturating
        self.histo.saturating_record_n(value, count);
    }

    /// Clears the values of the histogram
    pub fn clear(&mut self) {
        self.histo.reset();
    }

    /// Get the number of recorded values in the histogram.
    pub fn len(&self) -> u64 {
        self.histo.len()
    }

    /// Check if the histogram's recorded values are empty
    pub fn is_empty(&self) -> bool {
        self.histo.is_empty()
    }

    /// Get the lowest recorded value level in the histogram.
    /// If the histogram has no recorded values, the value returned will be 0.
    pub fn min(&self) -> u64 {
        self.histo.min()
    }

    /// Get the highest recorded value level in the histogram.
    /// If the histogram has no recorded values, the value returned is
    /// undefined.
    pub fn max(&self) -> u64 {
        self.histo.max()
    }

    /// Get the computed mean value of all recorded values in the histogram.
    pub fn mean(&self) -> f64 {
        self.histo.mean()
    }

    /// Get the computed standard deviation of all recorded
    /// values in the histogram
    pub fn stdev(&self) -> f64 {
        self.histo.stdev()
    }

    /// Get the value at the 90% quantile.
    pub fn p90(&self) -> u64 {
        self.histo.value_at_quantile(0.9)
    }

    /// Get the value at the 95% quantile.
    pub fn p95(&self) -> u64 {
        self.histo.value_at_quantile(0.95)
    }

    /// Get the value at the 99% quantile.
    pub fn p99(&self) -> u64 {
        self.histo.value_at_quantile(0.99)
    }

    /// Get the value at the 99.9% quantile.
    pub fn p999(&self) -> u64 {
        self.histo.value_at_quantile(0.999)
    }

    /// Get the value at the 99.99% quantile.
    pub fn p9999(&self) -> u64 {
        self.histo.value_at_quantile(0.9999)
    }
}

impl Serialize for HdrHistogram {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let hdr = &self.histo;

        /// A percentile of this histogram - for supporting serializers this
        /// will ignore the key (such as `90%ile`) and instead add a
        /// dimension to the metrics (such as `quantile=0.9`).
        macro_rules! ile {
            ($e:expr) => {
                &MetricAlias(concat!("!|quantile=", $e), hdr.value_at_quantile($e))
            };
        }

        /// A 'qualified' metric name - for supporting serializers this will
        /// prepend the metric name to this key, outputting
        /// `response_time_count`, for example rather than just `count`.
        macro_rules! qual {
            ($e:expr) => {
                &MetricAlias("<|", $e)
            };
        }

        use serde::ser::SerializeMap;

        let mut tup = serializer.serialize_map(Some(10))?;
        tup.serialize_entry("samples", qual!(hdr.len()))?;
        tup.serialize_entry("min", qual!(hdr.min()))?;
        tup.serialize_entry("max", qual!(hdr.max()))?;
        tup.serialize_entry("mean", qual!(hdr.mean()))?;
        tup.serialize_entry("stdev", qual!(hdr.stdev()))?;
        tup.serialize_entry("90%ile", ile!(0.9))?;
        tup.serialize_entry("95%ile", ile!(0.95))?;
        tup.serialize_entry("99%ile", ile!(0.99))?;
        tup.serialize_entry("99.9%ile", ile!(0.999))?;
        tup.serialize_entry("99.99%ile", ile!(0.9999))?;
        tup.end()
    }
}

/// This is a mocked 'newtype' (eg. `A(u64)`) that instead allows us to
/// define our own type name that doesn't have to abide by Rust's constraints
/// on type names. This allows us to do some manipulation of our metrics,
/// allowing us to add dimensionality to our metrics via key=value pairs, or
/// key manipulation on serializers that support it.
struct MetricAlias<T: Serialize>(&'static str, T);
impl<T: Serialize> Serialize for MetricAlias<T> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_newtype_struct(self.0, &self.1)
    }
}

impl Debug for HdrHistogram {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let hdr = &self.histo;
        let ile = |v| hdr.value_at_percentile(v);
        write!(
            f,
            "HdrHistogram {{
            samples: {}, min: {}, max: {}, mean: {}, stdev: {},
            90%ile = {}, 95%ile = {}, 99%ile = {}, 99.9%ile = {}, 99.99%ile = {} }}",
            hdr.len(),
            hdr.min(),
            hdr.max(),
            hdr.mean(),
            hdr.stdev(),
            ile(90.0),
            ile(95.0),
            ile(99.0),
            ile(99.9),
            ile(99.99)
        )
    }
}

use std::cell::RefCell;

impl Histogram for RefCell<HdrHistogram> {
    fn with_bound(max_value: u64) -> Self {
        RefCell::new(HdrHistogram::with_bound(max_value))
    }

    fn record(&self, value: u64) {
        self.borrow_mut().record(value);
    }
}

impl Clear for RefCell<HdrHistogram> {
    fn clear(&self) {
        self.borrow_mut().clear();
    }
}


================================================
FILE: metered/src/int_counter.rs
================================================
//! A module providing thread-safe and unsynchronized implementations for
//! Counters on various unsized integers.

use crate::{
    atomic::AtomicInt,
    clear::{Clear, Clearable},
    metric::Counter,
    num_wrapper::NumWrapper,
};
use std::cell::Cell;

macro_rules! impl_counter_for {
    ($int:path) => {
        impl Counter for Cell<$int> {
            fn incr_by(&self, count: usize) {
                let v = NumWrapper::<$int>::wrap(count);
                self.set(self.get().wrapping_add(v));
            }
        }

        impl Clear for Cell<$int> {
            fn clear(&self) {
                self.set(0);
            }
        }

        impl Clearable for Cell<$int> {
            fn is_cleared(&self) -> bool {
                self.get() == 0
            }
        }

        impl Counter for AtomicInt<$int> {
            fn incr_by(&self, count: usize) {
                let v = NumWrapper::<$int>::wrap(count);
                AtomicInt::<$int>::incr_by(&self, v);
            }
        }

        impl Clear for AtomicInt<$int> {
            fn clear(&self) {
                AtomicInt::<$int>::set(&self, 0);
            }
        }

        impl Clearable for AtomicInt<$int> {
            fn is_cleared(&self) -> bool {
                AtomicInt::<$int>::get(&self) == 0
            }
        }
    };
}

impl_counter_for!(u8);
impl_counter_for!(u16);
impl_counter_for!(u32);
impl_counter_for!(u64);
impl_counter_for!(u128);


================================================
FILE: metered/src/int_gauge.rs
================================================
//! A module providing thread-safe and unsynchronized implementations for Gauges
//! on various unsized integers.

use crate::{atomic::AtomicInt, metric::Gauge, num_wrapper::NumWrapper};
use std::cell::Cell;

macro_rules! impl_gauge_for {
    ($int:path) => {
        impl Gauge for Cell<$int> {
            fn incr_by(&self, count: usize) {
                let v = NumWrapper::<$int>::wrap(count);
                self.set(self.get().wrapping_add(v));
            }

            fn decr_by(&self, count: usize) {
                let v = NumWrapper::<$int>::wrap(count);
                self.set(self.get().wrapping_sub(v));
            }
        }

        impl Gauge for AtomicInt<$int> {
            fn incr_by(&self, count: usize) {
                let v = NumWrapper::<$int>::wrap(count);
                AtomicInt::<$int>::incr_by(&self, v);
            }

            fn decr_by(&self, count: usize) {
                let v = NumWrapper::<$int>::wrap(count);
                AtomicInt::<$int>::decr_by(&self, v);
            }
        }
    };
}

impl_gauge_for!(u8);
impl_gauge_for!(u16);
impl_gauge_for!(u32);
impl_gauge_for!(u64);
impl_gauge_for!(u128);


================================================
FILE: metered/src/lib.rs
================================================
//! # Fast, ergonomic metrics for Rust!
//!
//! Metered helps you measure the performance of your programs in production.
//! Inspired by Coda Hale's Java metrics library, Metered makes live
//! measurements easy by providing measurement declarative and procedural
//! macros, and a variety of useful metrics ready out-of-the-box:
//! * [`HitCount`]: a counter tracking how much a piece of code was hit.
//! * [`ErrorCount`]: a counter tracking how many errors were returned -- (works
//!   on any expression returning a std `Result`)
//! * [`InFlight`]: a gauge tracking how many requests are active
//! * [`ResponseTime`]: statistics backed by an HdrHistogram of the duration of
//!   an expression
//! * [`Throughput`]: statistics backed by an HdrHistogram of how many times an
//!   expression is called per second.
//!
//! These metrics are usually applied to methods, using provided procedural
//! macros that generate the boilerplate.
//!
//! To achieve higher performance, these stock metrics can be customized to use
//! non-thread safe (`!Sync`/`!Send`) datastructures, but they default to
//! thread-safe datastructures implemented using lock-free strategies where
//! possible. This is an ergonomical choice to provide defaults that work in all
//! situations.
//!
//! Metered is designed as a zero-overhead abstraction -- in the sense that the
//! higher-level ergonomics should not cost over manually adding metrics.
//! Notably, stock metrics will *not* allocate memory after they're initialized
//! the first time.  However, they are triggered at every method call and it can
//! be interesting to use lighter metrics (e.g
//! [`HitCount`]) in hot code paths and favour
//! heavier metrics ([`Throughput`],
//! [`ResponseTime`]) in higher-level entry
//! points.
//!
//! If a metric you need is missing, or if you want to customize a metric (for
//! instance, to track how many times a specific error occurs, or react
//! depending on your return type), it is possible to implement your own metrics
//! simply by implementing the [`Metric`] trait .
//!
//! Metered does not use statics or shared global state. Instead, it lets you
//! either build your own metric registry using the metrics you need, or can
//! generate a metric registry for you using method attributes. Metered will
//! generate one registry per `impl` block annotated with the `metered`
//! attribute, under the name provided as the `registry` parameter. By default,
//! Metered will expect the registry to be accessed as `self.metrics` but the
//! expression can be overridden with the `registry_expr` attribute parameter.
//! See the demos for more examples.
//!
//! Metered will generate metric registries that derive [`std::fmt::Debug`] and
//! [`serde::Serialize`] to extract your metrics easily. Metered generates one
//! sub-registry per method annotated with the `measure` attribute, hence
//! organizing metrics hierarchically. This ensures access time to metrics in
//! generated registries is always constant (and, when possible,
//! cache-friendly), without any overhead other than the metric itself.
//!
//! Metered will happily measure any method, whether it is `async` or not, and
//! the metrics will work as expected (e.g,
//! [`ResponseTime`] will return the completion
//! time across `await`'ed invocations).
//!
//! Metered's serialized metrics can be used in conjunction with
//! [`serde_prometheus`](https://github.com/w4/serde_prometheus) to publish
//! metrics to Prometheus.
//!
//! ## Example using procedural macros (recommended)
//!
//! ```
//! # extern crate metered;
//! # extern crate rand;
//!
//! use metered::{metered, Throughput, HitCount};
//!
//! #[derive(Default, Debug)]
//! pub struct Biz {
//!     metrics: BizMetrics,
//! }
//!
//! #[metered::metered(registry = BizMetrics)]
//! impl Biz {
//!     #[measure([HitCount, Throughput])]
//!     pub fn biz(&self) {        
//!         let delay = std::time::Duration::from_millis(rand::random::<u64>() % 200);
//!         std::thread::sleep(delay);
//!     }   
//! }
//!
//! # fn main() {
//! # }
//! ```
//!
//! In the snippet above, we will measure the
//! [`HitCount`] and
//! [`Throughput`] of the `biz` method.
//!
//! This works by first annotating the `impl` block with the `metered`
//! annotation and specifying the name Metered should give to the metric
//! registry (here `BizMetrics`). Later, Metered will assume the expression to
//! access that repository is `self.metrics`, hence we need a `metrics` field
//! with the `BizMetrics` type in `Biz`. It would be possible to use another
//! field name by specificying another registry expression, such as
//! `#[metered(registry = BizMetrics, registry_expr = self.my_custom_metrics)]`.
//!
//! Then, we must annotate which methods we wish to measure using the `measure`
//! attribute, specifying the metrics we wish to apply: the metrics here are
//! simply types of structures implementing the `Metric` trait, and you can
//! define your own. Since there is no magic, we must ensure `self.metrics` can
//! be accessed, and this will only work on methods with a `&self` or `&mut
//! self` receiver.
//!
//! ## Example of manually using metrics
//!
//! ```
//! use metered::{measure, HitCount, ErrorCount};
//!
//! #[derive(Default, Debug)]
//! struct TestMetrics {
//!     hit_count: HitCount,
//!     error_count: ErrorCount,
//! }
//!
//! fn test(should_fail: bool, metrics: &TestMetrics) -> Result<u32, &'static str> {
//!     let hit_count = &metrics.hit_count;
//!     let error_count = &metrics.error_count;
//!     measure!(hit_count, {
//!         measure!(error_count, {
//!             if should_fail {
//!                 Err("Failed!")
//!             } else {
//!                 Ok(42)
//!             }
//!         })
//!     })
//! }
//! ```
//!
//! The code above shows how different metrics compose, and in general the kind
//! of boilerplate generated by the `#[metered]` procedural macro.

#![deny(missing_docs)]
#![deny(warnings)]

pub mod atomic;
pub mod clear;
pub mod common;
pub mod hdr_histogram;
pub mod int_counter;
pub mod int_gauge;
pub mod metric;
pub(crate) mod num_wrapper;
pub mod time_source;

pub use common::{ErrorCount, HitCount, InFlight, ResponseTime, Throughput};
pub use metered_macro::{error_count, metered};
pub use metric::{Counter, Gauge, Histogram, Metric};

/// Re-export this type so 3rd-party crates don't need to depend on the
/// `aspect-rs` crate.
pub use aspect::Enter;

/// The `measure!` macro takes a reference to a metric and an expression.
///
/// It applies the metric and the expression is returned unchanged.
/// 
/// ```rust
/// use metered::{ResponseTime, measure};
/// 
/// let response_time: ResponseTime = ResponseTime::default();
/// 
/// measure!(&response_time, {
///     std::thread::sleep(std::time::Duration::from_millis(100));
/// });
/// 
/// assert!(response_time.histogram().mean() > 0.0);
/// ```
/// 
/// It also allows to pass an array of references, which will expand recursively.
/// 
/// ```rust
/// use metered::{HitCount, ResponseTime, measure};
/// 
/// let hit_count: HitCount = HitCount::default();
/// let response_time: ResponseTime = ResponseTime::default();
/// 
/// measure!([&hit_count, &response_time], {
///     std::thread::sleep(std::time::Duration::from_millis(100));
/// });
/// 
/// assert_eq!(hit_count.get(), 1);
/// assert!(response_time.histogram().mean() > 0.0);
/// ```
///
#[macro_export]
macro_rules! measure {
    ([$metric:expr], $expr:expr) => {{
        $crate::measure!($metric, $expr)
    }};
    
    ([$metric:expr, $($metrics:expr),*], $expr:expr) => {
        $crate::measure!($metric, $crate::measure!([$($metrics),*], $expr))
    };

    ($metric:expr, $e:expr) => {{
        let metric = $metric;
        let guard = $crate::metric::ExitGuard::new(metric);
        let mut result = $e;
        guard.on_result(&mut result);
        result
    }};
}

/// Serializer for values within a struct generated by
/// `metered::metered_error_variants` that adds an `error_kind` label when being
/// serialized by `serde_prometheus`.
pub fn error_variant_serializer<S: serde::Serializer, T: serde::Serialize>(
    value: &T,
    serializer: S,
) -> Result<S::Ok, S::Error> {
    serializer.serialize_newtype_struct("!|variant[::]==<", value)
}

/// Serializer for values within a struct generated by
/// `metered::metered_error_variants` that adds an `error_kind` label when being
/// serialized by `serde_prometheus`. If the `value` has been cleared. This
/// operation is a no-op and the value wont be written to the `serializer`.
pub fn error_variant_serializer_skip_cleared<
    S: serde::Serializer,
    T: serde::Serialize + clear::Clearable,
>(
    value: &T,
    serializer: S,
) -> Result<S::Ok, S::Error> {
    if value.is_cleared() {
        serializer.serialize_none()
    } else {
        error_variant_serializer(value, serializer)
    }
}

/// Trait applied to error enums by `#[metered::error_count]` to identify
/// generated error count structs.
pub trait ErrorBreakdown<C: metric::Counter> {
    /// The generated error count struct.
    type ErrorCount;
}

/// Generic trait for `ErrorBreakdown::ErrorCount` to increase error count for a
/// specific variant by 1.
pub trait ErrorBreakdownIncr<E> {
    /// Increase count for given variant by 1.
    fn incr(&self, e: &E);
}


================================================
FILE: metered/src/metric.rs
================================================
//! A module defining the [`Metric`] trait and common metric backends.

use crate::clear::{Clear, Clearable};
/// Re-export `aspect-rs`'s types to avoid crates depending on it.
pub use aspect::{Advice, Enter, OnResult, OnResultMut};
use serde::Serialize;
use std::marker::PhantomData;

/// A trait to implement to be used in the `measure!` macro
///
/// Metrics wrap expressions to measure them.
///
/// The return type, R, of the expression can be captured to perform special
/// handling.
pub trait Metric<R>: Default + OnResultMut<R> + Clear + Serialize {}

// Needed to force `measure!` to work only with the [`Metric`] trait.
#[doc(hidden)]
pub fn on_result<R, A: Metric<R>>(metric: &A, _enter: <A as Enter>::E, _result: &mut R) -> Advice {
    metric.on_result(_enter, _result)
}
/// Handles a metric's lifecycle, guarding against early returns and panics.
pub struct ExitGuard<'a, R, M: Metric<R>> {
    metric: &'a M,
    enter: Option<<M as Enter>::E>,
    _phantom: PhantomData<R>,
}

impl<'a, R, M: Metric<R>> ExitGuard<'a, R, M> {
    /// Enter a metric and create the guard for its exit.
    /// This calls [`aspect::Enter::enter`] on the metric internally.
    pub fn new(metric: &'a M) -> Self {
        Self {
            metric,
            enter: Some(metric.enter()),
            _phantom: PhantomData,
        }
    }

    /// If no unexpected exit occurred, record the expression's result.
    pub fn on_result(mut self, result: &mut R) {
        if let Some(enter) = self.enter.take() {
            self.metric.on_result(enter, result);
        } else {
            // OnResult called twice - we ignore
        }
    }
}

impl<'a, R, M: Metric<R>> Drop for ExitGuard<'a, R, M> {
    fn drop(&mut self) {
        if let Some(enter) = self.enter.take() {
            self.metric.leave_scope(enter);
        } else {
            // on_result was called, so the result was already recorded
        }
    }
}

/// A trait for Counters
pub trait Counter: Default + Clear + Clearable + Serialize {
    /// Increment the counter
    fn incr(&self) {
        self.incr_by(1)
    }

    /// Increment the counter by count in one step
    ///
    /// Supplying a count larger than the underlying counter's remaining
    /// capacity will wrap like [`u8::wrapping_add`] and similar methods.
    fn incr_by(&self, count: usize);
}

/// A trait for Gauges
pub trait Gauge: Default + Clear + Serialize {
    /// Increment the counter
    fn incr(&self) {
        self.incr_by(1)
    }

    /// Decrement the counter
    fn decr(&self) {
        self.decr_by(1)
    }

    /// Increment the gauge by count in one step
    ///
    /// Supplying a count larger than the underlying counter's remaining
    /// capacity will wrap like [`u8::wrapping_add`] and similar methods.
    fn incr_by(&self, count: usize);

    /// Decrement the gauge by count in one step
    ///
    /// Supplying a count larger than the underlying counter's current value
    /// will wrap like [`u8::wrapping_sub`] and similar methods.
    fn decr_by(&self, count: usize);
}

/// A trait for Histograms
pub trait Histogram: Clear + Serialize {
    /// Build a new histogram with the given max bounds
    fn with_bound(max_value: u64) -> Self;

    /// Record a value to the histogram.
    ///
    /// It will saturate if the value is higher than the histogram's
    /// `max_value`.
    fn record(&self, value: u64);
}


================================================
FILE: metered/src/num_wrapper.rs
================================================
use std::marker::PhantomData;

/// Metered metrics wrap when the counters are at capacity instead of
/// overflowing or underflowing.
///
/// This struct provides wrapping logic where a metric can be incremented or
/// decremented `N` times, where `N` is `usize`.
///
/// This is the most logical default:
/// * It is observable
/// * Metered should never panic business code
/// * While we could argue that gauges saturate at max capacity, doing
/// so will unbalance the gauge when decrementing the count after a saturated
/// add. Instead we guarantee that for all `N`, each `incr_by(N)` followed by a
/// `decr_by(N)` results in the original value.
///
/// Should we avoid calling `NumWrapper` with `count = 1`, i.e is the optimizer
/// able to get rid of the wrapping computations?  The Godbolt compiler explorer
/// shows that starting `opt-level = 1`, the generated call is equivalent.
/// Program below for future reference:
/// ```rust
/// pub fn wrap(count: usize) -> u8 {
///     (count % (u8::MAX as usize + 1)) as u8
/// }
///
/// pub fn naive(c: u8) -> u8 {
///     c.wrapping_add(wrap(1))
/// }
///
/// pub fn manual(c: u8) -> u8  {
///     c.wrapping_add(1)
/// }
///
///
/// pub fn main(){
///     let m = manual(42);
///     let n = naive(42);
///     println!("{n} {m}");
/// }
/// ```
pub(crate) struct NumWrapper<T>(PhantomData<T>);

macro_rules! impl_num_wrapper_for_smaller_than_usize {
    ($int:path) => {
        impl NumWrapper<$int> {
            /// Wrap count wrapped over $int
            pub(crate) fn wrap(count: usize) -> $int {
                (count % (<$int>::MAX as usize + 1)) as $int
            }
        }
    };
}

macro_rules! impl_num_wrapper_for_equal_or_larger_than_usize {
    ($int:path) => {
        impl NumWrapper<$int> {
            /// Return count as $int
            pub(crate) fn wrap(count: usize) -> $int {
                count as $int
            }
        }
    };
}

cfg_if::cfg_if! {
    if #[cfg(target_pointer_width = "8")] {
        impl_num_wrapper_for_equal_or_larger_than_usize!(u8);
        impl_num_wrapper_for_equal_or_larger_than_usize!(u16);
        impl_num_wrapper_for_equal_or_larger_than_usize!(u32);
        impl_num_wrapper_for_equal_or_larger_than_usize!(u64);
        impl_num_wrapper_for_equal_or_larger_than_usize!(u128);
    } else if #[cfg(target_pointer_width = "16")] {
        impl_num_wrapper_for_smaller_than_usize!(u8);
        impl_num_wrapper_for_equal_or_larger_than_usize!(u16);
        impl_num_wrapper_for_equal_or_larger_than_usize!(u32);
        impl_num_wrapper_for_equal_or_larger_than_usize!(u64);
        impl_num_wrapper_for_equal_or_larger_than_usize!(u128);
    } else if #[cfg(target_pointer_width = "32")] {
        impl_num_wrapper_for_smaller_than_usize!(u8);
        impl_num_wrapper_for_smaller_than_usize!(u16);
        impl_num_wrapper_for_equal_or_larger_than_usize!(u32);
        impl_num_wrapper_for_equal_or_larger_than_usize!(u64);
        impl_num_wrapper_for_equal_or_larger_than_usize!(u128);
    } else if #[cfg(target_pointer_width = "64")] {
        impl_num_wrapper_for_smaller_than_usize!(u8);
        impl_num_wrapper_for_smaller_than_usize!(u16);
        impl_num_wrapper_for_smaller_than_usize!(u32);
        impl_num_wrapper_for_equal_or_larger_than_usize!(u64);
        impl_num_wrapper_for_equal_or_larger_than_usize!(u128);
    } else if #[cfg(target_pointer_width = "128")] {
        impl_num_wrapper_for_smaller_than_usize!(u8);
        impl_num_wrapper_for_smaller_than_usize!(u16);
        impl_num_wrapper_for_smaller_than_usize!(u32);
        impl_num_wrapper_for_smaller_than_usize!(u64);
        impl_num_wrapper_for_equal_or_larger_than_usize!(u128);
    } else {
        compile_error!("Unsupported architecture - unhandled pointer size.");
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use proptest::prelude::*;

    // test with u8 for more wrapping - same model/properties applies to other ints.
    fn incr_by(cc: u8, count: usize) -> u8 {
        let v = NumWrapper::<u8>::wrap(count);
        cc.wrapping_add(v)
    }
    fn incr_by_naive(mut cc: u8, count: usize) -> u8 {
        for _ in 0..count {
            cc = cc.wrapping_add(1);
        }
        cc
    }

    fn decr_by(cc: u8, count: usize) -> u8 {
        let v = NumWrapper::<u8>::wrap(count);
        cc.wrapping_sub(v)
    }
    fn decr_by_naive(mut cc: u8, count: usize) -> u8 {
        for _ in 0..count {
            cc = cc.wrapping_sub(1);
        }
        cc
    }

    proptest! {
        #[test]
        fn test_wrapping_incr(x: u8, y in 0..4096usize) {
            // Tests if calling incr() Y times returns the same value
            // as the optimized version
            assert_eq!(incr_by_naive(x, y), incr_by(x, y));
        }

        #[test]
        fn test_wrapping_decr(x: u8,  y in 0..4096usize) {
            // Tests if calling decr() Y times returns the same value
            // as the optimized version
            assert_eq!(decr_by_naive(x, y), decr_by(x, y));
        }

        #[test]
        fn test_wrapping_incr_decr_symmetric(x: u8, y: usize) {
            // reduce strategy space, usize takes too long
            // Tests if calling decr() Y times on incr() Y times returns
            // the original value
            assert_eq!(x, decr_by(incr_by(x, y), y));
        }
    }
}


================================================
FILE: metered/src/time_source.rs
================================================
//! A module for Time Sources.

use std::convert::TryFrom;
use std::time::Duration;

/// A trait for any time source providing time measurements in milliseconds.
///
/// It is useful to let users provide an unsynchronized  (`!Send`/`!Sync`) time
/// source, unlike std's `Instant`.
pub trait Instant {
    /// Creates a new Instant representing the current time.
    fn now() -> Self;

    /// Returns the elapsed time since an Instant was created.
    ///
    /// The unit depends on the Instant's resolution, as defined by the
    /// `ONE_SEC` constant.
    fn elapsed_time(&self) -> u64;

    /// Return the amount of units from a Duration.
    fn units(duration: Duration) -> u64;

    /// One second in the instant units.
    const ONE_SEC: u64;
}

/// A new-type wrapper for std Instants and Metered's
/// [Instant] trait that measures time in milliseconds.
#[derive(Debug, Clone)]
pub struct StdInstant(std::time::Instant);
impl Instant for StdInstant {
    const ONE_SEC: u64 = 1_000;

    fn now() -> Self {
        StdInstant(std::time::Instant::now())
    }

    fn elapsed_time(&self) -> u64 {
        let elapsed = self.0.elapsed();

        elapsed.as_secs() * Self::ONE_SEC + u64::from(elapsed.subsec_millis())
    }

    fn units(duration: Duration) -> u64 {
        u64::try_from(duration.as_millis()).unwrap_or(u64::MAX)
    }
}

/// A new-type wrapper for std Instants and Metered's
/// [Instant] trait that measures time in microseconds.
#[derive(Debug, Clone)]
pub struct StdInstantMicros(std::time::Instant);
impl Instant for StdInstantMicros {
    const ONE_SEC: u64 = 1_000_000;

    fn now() -> Self {
        StdInstantMicros(std::time::Instant::now())
    }

    fn elapsed_time(&self) -> u64 {
        let elapsed = self.0.elapsed();

        elapsed.as_secs() * Self::ONE_SEC + u64::from(elapsed.subsec_micros())
    }

    fn units(duration: Duration) -> u64 {
        u64::try_from(duration.as_micros()).unwrap_or(u64::MAX)
    }
}


================================================
FILE: metered-macro/Cargo.toml
================================================
[package]
name = "metered-macro"
version = "0.9.0"
authors = ["Simon Chemouil <simon.chemouil@lambdacube.fr>"]
license = "Apache-2.0 OR MIT"
readme = "../README.md"
keywords = ["metrics", "macro"]
repository = "https://github.com/magnet/metered-rs"
description = """
Fast, ergonomic metrics for Rust!
"""
categories = ["rust-patterns", "development-tools::profiling", "data-structures", "algorithms", "asynchronous"]
edition = "2018"

[dependencies]
syn = {version= "1.0", features = ["full"] }
aspect-weave = "0.2"
synattra = "0.2"
quote = "1.0"
proc-macro2 = "1.0"
heck = "0.4"
indexmap = "1.8"

[dev-dependencies]
serde = { version = "1.0", features = ["derive"] }
metered = { path = "../metered" }
thiserror = "1.0"
rand = "0.8"

[features]
# When enabled, the error count macro will skip serializing cleared entries (e.g counters with value 0)
# This can be overridden with the `skip_cleared` macro attribute
error-count-skip-cleared-by-default = []

[lib]
proc-macro = true

================================================
FILE: metered-macro/src/error_count.rs
================================================
use crate::error_count_opts::ErrorCountKeyValAttribute;
use heck::ToSnakeCase;
use proc_macro::TokenStream;
use syn::{Attribute, Field, Fields, Ident, ItemEnum};

pub fn error_count(attrs: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
    let attrs: ErrorCountKeyValAttribute = syn::parse(attrs)?;
    let attrs = attrs.to_error_count_opts();
    let vis = attrs.visibility;
    let metrics_ident = attrs.name_ident;

    let mut input: ItemEnum = syn::parse(item)?;

    let nested_attrs = get_nested_attrs(&mut input)?;

    // get the type of the metric for each variant, most of the time this will be
    // `C`, but if `#[nested(Abc)]` is on a variant field, the type will instead
    // be set to `Abc` and incrs will be delegated there
    let metric_type = nested_attrs
        .iter()
        .map(|(_, v)| {
            if let Some((field, attr)) = v {
                let error_type = &field.ty;
                attr.parse_args::<proc_macro2::TokenStream>()
                    .unwrap_or_else(
                        |_| quote!(<#error_type as metered::ErrorBreakdown<C>>::ErrorCount),
                    )
            } else {
                quote!(C)
            }
        })
        .collect::<Vec<_>>();

    let ident = &input.ident;

    let variants = input.variants.iter().map(|v| &v.ident);
    let stringified_variants = input.variants.iter().map(|v| v.ident.to_string());
    let snake_variants: Vec<Ident> = input
        .variants
        .iter()
        .map(|v| Ident::new(&v.ident.to_string().to_snake_case(), v.ident.span()))
        .collect();

    // copy #[cfg(..)] attributes from the variant and apply them to the
    // corresponding error in our struct so we don't point to an invalid variant
    // in certain configurations.
    let cfg_attrs: Vec<Vec<&Attribute>> = input
        .variants
        .iter()
        .map(|v| v.attrs.iter().filter(|v| v.path.is_ident("cfg")).collect())
        .collect();

    // generate unbound arg params for each enum variant
    let variants_args = nested_attrs
        .iter()
        .map(|(fields, nested_attr)| match &fields {
            syn::Fields::Named(_) => {
                if let Some((field, _)) = nested_attr {
                    let key = field.ident.as_ref().expect("field missing ident");
                    quote!({ #key, .. })
                } else {
                    quote!({ .. })
                }
            }
            syn::Fields::Unnamed(_) => {
                let args = fields.iter().map(|field| {
                    if field.attrs.iter().any(|attr| attr.path.is_ident("nested")) {
                        quote!(nested)
                    } else {
                        quote!(_)
                    }
                });
                quote! {
                    (#( #args, )*)
                }
            }
            syn::Fields::Unit => quote!(),
        });

    // generate incr calls for each variant, if a field is marked with `#[nested]`,
    // the incr is instead delegated there
    let variant_incr_call =
        nested_attrs
            .iter()
            .zip(snake_variants.iter())
            .map(|((_, nested_attr), ident)| {
                if let Some((field, attr)) = nested_attr {
                    let inner_val_ident = field
                        .ident
                        .clone()
                        .unwrap_or_else(|| Ident::new("nested", attr.bracket_token.span));
                    quote! {{
                        self.#ident.incr(#inner_val_ident);
                    }}
                } else {
                    quote!(self.#ident.incr())
                }
            });

    let skip_cleared = attrs.skip_cleared;
    let serializer = nested_attrs.iter().map(|(_, nested_attr)| {
        if skip_cleared && nested_attr.is_none() {
            quote!("metered::error_variant_serializer_skip_cleared")
        } else {
            quote!("metered::error_variant_serializer")
        }
    });

    Ok(quote! {
        #input

        #[derive(serde::Serialize, Default, Debug)]
        #[allow(missing_docs)]
        #vis struct #metrics_ident<C: metered::metric::Counter = metered::atomic::AtomicInt<u64>> {
            #[serde(skip)]
            __phantom: std::marker::PhantomData<C>,
            #(
                #(#cfg_attrs)*
                #[serde(rename = #stringified_variants, serialize_with = #serializer)]
                pub #snake_variants: #metric_type,
            )*
        }

        impl<C: metered::metric::Counter> metered::ErrorBreakdownIncr<#ident> for #metrics_ident<C> {
            fn incr(&self, err: &#ident) {
                match err {
                    #( #(#cfg_attrs)* #ident::#variants #variants_args => #variant_incr_call, )*
                }
            }
        }

        impl<C: metered::metric::Counter> metered::clear::Clear for #metrics_ident<C> {
            fn clear(&self) {
                #( #(#cfg_attrs)* self.#snake_variants.clear(); )*
            }
        }

        impl<T, C: metered::metric::Counter> metered::metric::Metric<Result<T, #ident>> for #metrics_ident<C> {}

        impl<C: metered::metric::Counter> metered::metric::Enter for #metrics_ident<C> {
            type E = ();
            fn enter(&self) {}
        }

        impl<T, C: metered::metric::Counter> metered::metric::OnResult<Result<T, #ident>> for #metrics_ident<C> {
            fn on_result(&self, (): (), r: &Result<T, #ident>) -> metered::metric::Advice {
                if let Err(e) = r {
                    metered::ErrorBreakdownIncr::incr(self, e);
                }
                metered::metric::Advice::Return
            }
        }

        impl<C: metered::metric::Counter> metered::ErrorBreakdown<C> for #ident {
            type ErrorCount = #metrics_ident<C>;
        }
    }.into())
}

type FieldWithNestedAttribute = Option<(Field, Attribute)>;

/// Gets all variants from the given `ItemEnum`, and returns `Some(Field,
/// Attribute)` along with each variant if one of fields contained a `#[nested]`
/// attribute.
///
/// If a `#[nested]` attribute is found, then the attribute itself removed from
/// `input` so that we don't get "unrecognised attribute" errors.
fn get_nested_attrs(input: &mut ItemEnum) -> syn::Result<Vec<(Fields, FieldWithNestedAttribute)>> {
    let attrs = input
        .variants
        .iter_mut()
        .map(|v| {
            // clone fields before we do any mutation on it so consumers can figure out the
            // position of #[nested] fields.
            let fields = v.fields.clone();

            let inner_fields = match &mut v.fields {
                syn::Fields::Named(v) => &mut v.named,
                syn::Fields::Unnamed(v) => &mut v.unnamed,
                _ => return Ok((fields, None)),
            };

            // field containing the nested attribute, along with the attribute itself
            let mut nested_attr = None;

            for field in inner_fields {
                if let Some(pos) = field.attrs.iter().position(|a| a.path.is_ident("nested")) {
                    let attr = field.attrs.remove(pos);

                    // if we've already found a nested attribute on a field in the current variant,
                    // throw an error
                    if nested_attr.is_some() {
                        return Err(syn::Error::new(
                            attr.bracket_token.span,
                            "Can't declare `#[nested]` on more than one field in a single variant",
                        ));
                    }

                    nested_attr = Some((field.clone(), attr.clone()));
                }
            }

            Ok((fields, nested_attr))
        })
        .collect::<syn::Result<Vec<_>>>()?;

    Ok(attrs)
}


================================================
FILE: metered-macro/src/error_count_opts.rs
================================================
//! The module supporting `#[error_count]` options

use syn::{
    parse::{Parse, ParseStream},
    Result,
};

use synattra::{types::KVOption, *};

use std::borrow::Cow;

pub struct ErrorCountOpts<'a> {
    pub name_ident: &'a syn::Ident,
    pub visibility: Cow<'a, syn::Visibility>,
    pub skip_cleared: bool,
}

pub struct ErrorCountKeyValAttribute {
    pub values: syn::punctuated::Punctuated<ErrorCountOption, Token![,]>,
}

impl ErrorCountKeyValAttribute {
    fn validate(&self, input: ParseStream<'_>) -> Result<()> {
        self.values
            .iter()
            .filter_map(|opt| {
                if let ErrorCountOption::Name(tpe) = opt {
                    Some(&tpe.value)
                } else {
                    None
                }
            })
            .next()
            .ok_or_else(|| input.error("missing `name` attribute."))?;

        let opt_types: std::collections::HashMap<_, _> = self
            .values
            .iter()
            .map(|opt| (std::mem::discriminant(opt), opt.as_str()))
            .collect();

        for (opt_type, opt_name) in opt_types.iter() {
            let count = self
                .values
                .iter()
                .filter(|&opt| std::mem::discriminant(opt) == *opt_type)
                .count();
            if count > 1 {
                let error = format!("`{}` attribute is defined more than once.", opt_name);
                return Err(input.error(error));
            }
        }

        Ok(())
    }

    pub fn to_error_count_opts(&self) -> ErrorCountOpts<'_> {
        let name_ident = self
            .values
            .iter()
            .filter_map(|opt| {
                if let ErrorCountOption::Name(tpe) = opt {
                    Some(&tpe.value)
                } else {
                    None
                }
            })
            .next()
            .expect("There should be a name! This error cannot happen if the structure has been validated first!");

        let visibility = self
            .values
            .iter()
            .filter_map(|opt| {
                if let ErrorCountOption::Visibility(tpe) = opt {
                    Some(&tpe.value)
                } else {
                    None
                }
            })
            .next()
            .map(Cow::Borrowed)
            .unwrap_or_else(|| {
                Cow::Owned(syn::parse_str::<syn::Visibility>("pub(crate)").unwrap())
            });

        let skip_cleared = self
            .values
            .iter()
            .filter_map(|opt| {
                if let ErrorCountOption::SkipCleared(tpe) = opt {
                    Some(&tpe.value)
                } else {
                    None
                }
            })
            .next()
            .map(|value| value.value)
            .unwrap_or(cfg!(feature = "error-count-skip-cleared-by-default"));

        ErrorCountOpts {
            name_ident,
            visibility,
            skip_cleared,
        }
    }
}

impl Parse for ErrorCountKeyValAttribute {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        let this = ErrorCountKeyValAttribute {
            values: input.parse_terminated(ErrorCountOption::parse)?,
        };

        this.validate(input)?;

        Ok(this)
    }
}

mod kw {
    syn::custom_keyword!(name);
    syn::custom_keyword!(visibility);
    syn::custom_keyword!(skip_cleared);
}

pub type ErrorCountNameOption = KVOption<kw::name, syn::Ident>;

pub type ErrorCountVisibilityOption = KVOption<kw::visibility, syn::Visibility>;

pub type ErrorCountSkipClearedOption = KVOption<kw::skip_cleared, syn::LitBool>;

#[allow(clippy::large_enum_variant)]
pub enum ErrorCountOption {
    Name(ErrorCountNameOption),
    Visibility(ErrorCountVisibilityOption),
    SkipCleared(ErrorCountSkipClearedOption),
}

impl ErrorCountOption {
    pub fn as_str(&self) -> &str {
        use syn::token::Token;
        match self {
            ErrorCountOption::Name(_) => <kw::name>::display(),
            ErrorCountOption::Visibility(_) => <kw::visibility>::display(),
            ErrorCountOption::SkipCleared(_) => <kw::skip_cleared>::display(),
        }
    }
}

impl Parse for ErrorCountOption {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        if ErrorCountNameOption::peek(input) {
            Ok(input.parse_as(ErrorCountOption::Name)?)
        } else if ErrorCountVisibilityOption::peek(input) {
            Ok(input.parse_as(ErrorCountOption::Visibility)?)
        } else if ErrorCountSkipClearedOption::peek(input) {
            Ok(input.parse_as(ErrorCountOption::SkipCleared)?)
        } else {
            let err = format!("invalid error_count option: {}", input);
            Err(input.error(err))
        }
    }
}


================================================
FILE: metered-macro/src/lib.rs
================================================
//! Procedural macros for Metered, a metric library for Rust.
//!
//! Please check the Metered crate for more documentation.

#![deny(warnings)]
// The `quote!` macro requires deep recursion.
#![recursion_limit = "512"]

#[macro_use]
extern crate syn;
#[macro_use]
extern crate quote;

mod error_count;
mod error_count_opts;
mod measure_opts;
mod metered;
mod metered_opts;

use proc_macro::TokenStream;

/// A procedural macro that generates a metric registry for an `impl` block.
///
/// ```
/// use metered::{metered, Throughput, HitCount};
///
/// #[derive(Default, Debug)]
/// pub struct Biz {
///     metrics: BizMetrics,
/// }
///
/// #[metered::metered(registry = BizMetrics)]
/// impl Biz {
///     #[measure([HitCount, Throughput])]
///     pub fn biz(&self) {        
///         let delay = std::time::Duration::from_millis(rand::random::<u64>() % 200);
///         std::thread::sleep(delay);
///     }   
/// }
/// #
/// # let biz = Biz::default();
/// # biz.biz();
/// # assert_eq!(biz.metrics.biz.hit_count.0.get(), 1);
/// ```
///
/// ### The `metered` attribute
///
/// `#[metered(registry = YourRegistryName, registry_expr =
/// self.wrapper.my_registry)]`
///
/// `registry` is mandatory and must be a valid Rust ident.
///
/// `registry_expr` defaults to `self.metrics`, alternate values must be a valid
/// Rust expression.
///
/// ### The `measure` attribute
///
/// Single metric:
///
/// `#[measure(path::to::MyMetric<u64>)]`
///
/// or:
///
/// `#[measure(type = path::to::MyMetric<u64>)]`
///
/// Multiple metrics:
///
/// `#[measure([path::to::MyMetric<u64>, path::AnotherMetric])]`
///
/// or
///
/// `#[measure(type = [path::to::MyMetric<u64>, path::AnotherMetric])]`
///
/// The `type` keyword is allowed because other keywords are planned for future
/// extra attributes (e.g, instantation options).
///
/// When `measure` attribute is applied to an `impl` block, it applies for every
/// method that has a `measure` attribute. If a method does not need extra
/// measure infos, it is possible to annotate it with simply `#[measure]` and
/// the `impl` block's `measure` configuration will be applied.
///
/// The `measure` keyword can be added several times on an `impl` block or
/// method, which will add to the list of metrics applied. Adding the same
/// metric several time will lead in a name clash.

#[proc_macro_attribute]
pub fn metered(attrs: TokenStream, item: TokenStream) -> TokenStream {
    metered::metered(attrs, item).unwrap_or_else(|e| TokenStream::from(e.to_compile_error()))
}

/// A procedural macro that generates a new metric that measures the amount
/// of times each variant of an error has been thrown, to be used as
/// crate-specific replacement for `metered::ErrorCount`.
///
/// ```
/// # use metered_macro::{metered, error_count};
/// # use thiserror::Error;
/// #
/// #[error_count(name = LibErrorCount, visibility = pub)]
/// #[derive(Debug, Error)]
/// pub enum LibError {
/// #   #[error("read error")]
///     ReadError,
/// #   #[error("init error")]
///     InitError,
/// }
///
/// #[error_count(name = ErrorCount, visibility = pub)]
/// #[derive(Debug, Error)]
/// pub enum Error {
/// #   #[error("error from lib: {0}")]
///     MyLibrary(#[from] #[nested] LibError),
/// }
///
/// #[derive(Default, Debug)]
/// pub struct Baz {
///     metrics: BazMetrics,
/// }
///
/// #[metered(registry = BazMetrics)]
/// impl Baz {
///     #[measure(ErrorCount)]
///     pub fn biz(&self) -> Result<(), Error> {        
///         Err(LibError::InitError.into())
///     }   
/// }
///
/// let baz = Baz::default();
/// baz.biz();
/// assert_eq!(baz.metrics.biz.error_count.my_library.read_error.get(), 0);
/// assert_eq!(baz.metrics.biz.error_count.my_library.init_error.get(), 1);
/// ```
///
/// - `name` is required and must be a valid Rust ident, this is the name of the
///   generated struct containing a counter for each enum variant.
/// - `visibility` specifies to visibility of the generated struct, it defaults
///   to `pub(crate)`.
/// - `skip_cleared` allows to make the serializer skip "cleared" entries, that
///   is entries for which the `Clearable::is_cleared` function returns true
///   (for counters, by default, whether they are 0). It defaults to whether the
///   feature `error-count-skip-cleared-by-default` is enabled. By default, this
///   feature is disabled, and no entry will be skipped.
///
///
/// The `error_count` macro may only be applied to any enums that have a
/// `std::error::Error` impl. The generated struct may then be included
/// in `measure` attributes to measure the amount of errors returned of
/// each variant defined in your error enum.

#[proc_macro_attribute]
pub fn error_count(attrs: TokenStream, item: TokenStream) -> TokenStream {
    error_count::error_count(attrs, item)
        .unwrap_or_else(|e| TokenStream::from(e.to_compile_error()))
}


================================================
FILE: metered-macro/src/measure_opts.rs
================================================
//! The module supporting `#[measure]` options

use syn::{
    parse::{Parse, ParseStream},
    Result,
};

use synattra::{
    types::{extra::InvokePath, KVOption, MultipleVal},
    ParseStreamExt,
};

pub struct MeasureRequest<'a> {
    pub tpe: &'a syn::TypePath,
    pub field_name: String,
    pub debug: Option<&'a InvokePath>,
}

impl<'a> MeasureRequest<'a> {
    pub fn ident(&self) -> syn::Ident {
        syn::Ident::new(&self.field_name, proc_macro2::Span::call_site())
    }

    pub fn type_path(&self) -> &syn::TypePath {
        self.tpe
    }
}

pub enum MeasureRequestAttribute {
    Empty,
    NonEmpty(NonEmptyMeasureRequestAttribute),
}

impl MeasureRequestAttribute {
    pub fn to_requests(&self) -> Vec<MeasureRequest<'_>> {
        match self {
            MeasureRequestAttribute::Empty => Vec::new(),
            MeasureRequestAttribute::NonEmpty(req) => req.to_requests(),
        }
    }
}

impl Parse for MeasureRequestAttribute {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        if input.is_empty() {
            Ok(MeasureRequestAttribute::Empty)
        } else {
            Ok(MeasureRequestAttribute::NonEmpty(
                NonEmptyMeasureRequestAttribute::parse(input)?,
            ))
        }
    }
}

pub struct NonEmptyMeasureRequestAttribute {
    pub paren_token: syn::token::Paren,
    pub inner: Option<MeasureRequestAttributeInner>,
}

impl NonEmptyMeasureRequestAttribute {
    pub fn to_requests(&self) -> Vec<MeasureRequest<'_>> {
        if let Some(ref inner) = self.inner {
            inner.to_requests()
        } else {
            Vec::new()
        }
    }
}

impl Parse for NonEmptyMeasureRequestAttribute {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        let content;
        let paren_token = parenthesized!(content in input);

        let inner = if content.is_empty() {
            None
        } else {
            Some(content.parse()?)
        };

        let this = NonEmptyMeasureRequestAttribute { paren_token, inner };

        Ok(this)
    }
}

pub enum MeasureRequestAttributeInner {
    TypePath(MeasureRequestTypePathAttribute),
    KeyVal(MeasureRequestKeyValAttribute),
}

impl MeasureRequestAttributeInner {
    pub fn to_requests(&self) -> Vec<MeasureRequest<'_>> {
        match self {
            MeasureRequestAttributeInner::TypePath(type_path) => type_path.to_requests(),
            MeasureRequestAttributeInner::KeyVal(key_val) => key_val.to_requests(),
        }
    }
}

impl Parse for MeasureRequestAttributeInner {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        input
            .try_parse_as(MeasureRequestAttributeInner::TypePath)
            .or_else(|_| input.try_parse_as(MeasureRequestAttributeInner::KeyVal))
            .map_err(|_| {
                let err = format!("invalid format for measure attribute: {}", input);
                input.error(err)
            })
    }
}

pub struct MeasureRequestTypePathAttribute {
    pub type_paths: MultipleVal<syn::TypePath>,
}

impl MeasureRequestTypePathAttribute {
    pub fn to_requests(&self) -> Vec<MeasureRequest<'_>> {
        let mut v = Vec::new();
        for type_path in self.type_paths.iter() {
            let field_name = make_field_name(type_path);
            v.push(MeasureRequest {
                tpe: type_path,
                field_name,
                debug: None,
            })
        }
        v
    }
}

impl Parse for MeasureRequestTypePathAttribute {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        Ok(MeasureRequestTypePathAttribute {
            type_paths: input.parse()?,
        })
    }
}

pub struct MeasureRequestKeyValAttribute {
    pub values: syn::punctuated::Punctuated<MeasureOptions, Token![,]>,
}

impl MeasureRequestKeyValAttribute {
    fn validate(&self, input: ParseStream<'_>) -> Result<()> {
        self.values
            .iter()
            .filter_map(|opt| {
                if let MeasureOptions::Type(tpe) = opt {
                    Some(&tpe.value)
                } else {
                    None
                }
            })
            .next()
            .ok_or_else(|| {
                input.error(
                    "missing `type` attribute with a path to a valid metered::Metric struct.",
                )
            })?;

        let opt_types: std::collections::HashMap<_, _> = self
            .values
            .iter()
            .map(|opt| (std::mem::discriminant(opt), opt.as_str()))
            .collect();

        for (opt_type, opt_name) in opt_types.iter() {
            let count = self
                .values
                .iter()
                .filter(|&opt| std::mem::discriminant(opt) == *opt_type)
                .count();
            if count > 1 {
                let error = format!("`{}` attribute is defined more than once.", opt_name);
                return Err(input.error(error));
            }
        }

        // self.values.iter().

        Ok(())
    }

    pub fn to_requests(&self) -> Vec<MeasureRequest<'_>> {
        let type_paths = self
            .values
            .iter()
            .filter_map(|opt| {
                if let MeasureOptions::Type(tpe) = opt {
                    Some(&tpe.value)
                } else {
                    None
                }
            })
            .next()
            .expect("There should be a type! This error cannot happen if the structure has been validated first!");
        let debug = self
            .values
            .iter()
            .filter_map(|opt| {
                if let MeasureOptions::Debug(dbg) = opt {
                    Some(&dbg.value)
                } else {
                    None
                }
            })
            .next();

        let mut v = Vec::new();
        for type_path in type_paths.iter() {
            let field_name = make_field_name(type_path);
            v.push(MeasureRequest {
                tpe: type_path,
                field_name,
                debug,
            })
        }
        v
    }
}

fn make_field_name(type_path: &syn::TypePath) -> String {
    use heck::ToSnakeCase;
    type_path
        .path
        .segments
        .last()
        .unwrap() // never empty
        .ident
        .to_string()
        .to_snake_case()
}

impl Parse for MeasureRequestKeyValAttribute {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        let this = MeasureRequestKeyValAttribute {
            values: input.parse_terminated(MeasureOptions::parse)?,
        };

        this.validate(input)?;

        Ok(this)
    }
}

mod kw {
    syn::custom_keyword!(debug);
}

pub type MeasureTypeOption = KVOption<syn::Token![type], MultipleVal<syn::TypePath>>;
pub type MeasureDebugOption = KVOption<kw::debug, InvokePath>;

pub enum MeasureOptions {
    Type(MeasureTypeOption),
    Debug(MeasureDebugOption),
}

impl MeasureOptions {
    pub fn as_str(&self) -> &str {
        use syn::token::Token;
        match self {
            MeasureOptions::Type(_) => <syn::Token![type]>::display(),
            MeasureOptions::Debug(_) => <kw::debug>::display(),
        }
    }
}

impl Parse for MeasureOptions {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        if MeasureTypeOption::peek(input) {
            Ok(input.parse_as(MeasureOptions::Type)?)
        } else if MeasureDebugOption::peek(input) {
            Ok(input.parse_as(MeasureOptions::Debug)?)
        } else {
            let err = format!("invalid measure option: {}", input);
            Err(input.error(err))
        }
    }
}


================================================
FILE: metered-macro/src/metered.rs
================================================
//! The module supporting #[metered]

use proc_macro::TokenStream;

use crate::{measure_opts::MeasureRequestAttribute, metered_opts::MeteredKeyValAttribute};

use aspect_weave::*;
use std::rc::Rc;
use synattra::ParseAttributes;

pub fn metered(attrs: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
    let woven_impl_block = weave_impl_block::<MeteredWeave>(attrs, item)?;

    let impl_block = &woven_impl_block.woven_block;
    let metered = &woven_impl_block.main_attributes.to_metered();
    let measured = &woven_impl_block.woven_fns;
    let registry_name = &metered.registry_name;
    let registry_ident = &metered.registry_ident;
    let visibility = &metered.visibility;

    let mut code = quote! {};

    let mut reg_fields = quote! {};
    let mut reg_clears = quote! {};

    for (fun_name, _) in measured.iter() {
        use heck::ToUpperCamelCase;
        let fun_reg_name = format!(
            "{}{}",
            registry_name,
            fun_name.to_string().to_upper_camel_case()
        );
        let fun_registry_ident = syn::Ident::new(&fun_reg_name, impl_block.impl_token.span);

        reg_fields = quote! {
            #reg_fields
            pub #fun_name : #fun_registry_ident,
        };

        reg_clears = quote! {
            #reg_clears
            self.#fun_name.clear();
        };
    }

    code = quote! {
        #code

        #[derive(Debug, Default, serde::Serialize)]
        #[allow(missing_docs)]
        #visibility struct #registry_ident {
            #reg_fields
        }


        impl metered::clear::Clear for #registry_ident {
            fn clear(&self) {
                #reg_clears
            }
        }
    };

    drop(reg_fields);

    for (fun_name, measure_request_attrs) in measured.iter() {
        use heck::ToUpperCamelCase;
        let fun_reg_name = format!(
            "{}{}",
            registry_name,
            fun_name.to_string().to_upper_camel_case()
        );
        let fun_registry_ident = syn::Ident::new(&fun_reg_name, impl_block.impl_token.span);

        let mut fun_reg_fields = quote! {};
        let mut fun_reg_clears = quote! {};

        for measure_req_attr in measure_request_attrs.iter() {
            let metric_requests = measure_req_attr.to_requests();

            for metric in metric_requests.iter() {
                let metric_field = metric.ident();
                let metric_type = metric.type_path();

                fun_reg_fields = quote! {
                    #fun_reg_fields
                    pub #metric_field : #metric_type,
                };

                fun_reg_clears = quote! {
                    #fun_reg_clears
                    self.#metric_field.clear();
                };
            }
        }

        code = quote! {
            #code

            #[derive(Debug, Default, serde::Serialize)]
            #[allow(missing_docs)]
            #visibility struct #fun_registry_ident {
                #fun_reg_fields
            }

            impl metered::clear::Clear for #fun_registry_ident {
                fn clear(&self) {
                    #fun_reg_clears
                }
            }
        };
    }

    code = quote! {
        #impl_block

        #code
    };

    let result: TokenStream = code.into();
    // println!("Result {}", result.to_string());
    Ok(result)
}

struct MeteredWeave;
impl Weave for MeteredWeave {
    type MacroAttributes = MeteredKeyValAttribute;

    fn update_fn_block(
        item_fn: &syn::ImplItemMethod,
        main_attr: &Self::MacroAttributes,
        fn_attr: &[Rc<<Self as ParseAttributes>::Type>],
    ) -> syn::Result<syn::Block> {
        let metered = main_attr.to_metered();
        let ident = &item_fn.sig.ident;
        let block = &item_fn.block;
        // We must alter the block to capture early returns
        // using a closure, and handle the async case.

        let outer_block = if item_fn.sig.asyncness.is_some() {
            // For versions before `.await` stabilization,
            // We cannot use the `await` keyword in the `quote!` macro
            // We'd like to simply be able to put this in the `quote!`:
            //
            // (move || async move #block)().await`

            let await_fut = syn::parse_str::<syn::Expr>("fut.await")?;
            quote! {
                {
                    let fut = (move || async move #block)();
                    #await_fut
                }
            }
        } else {
            quote! {
                (move || #block)()
            }
        };

        let r = measure_list(&metered.registry_expr, ident, fn_attr, outer_block);

        let new_block = syn::parse2::<syn::Block>(r)?;
        Ok(new_block)
    }
}
impl ParseAttributes for MeteredWeave {
    type Type = MeasureRequestAttribute;

    // const
    fn fn_attr_name() -> &'static str {
        "measure"
    }
}

fn measure_list(
    registry_expr: &syn::Expr,
    fun_ident: &syn::Ident,
    measure_request_attrs: &[Rc<MeasureRequestAttribute>],
    mut inner: proc_macro2::TokenStream,
) -> proc_macro2::TokenStream {
    // Recursive macro invocations
    for measure_req_attr in measure_request_attrs.iter() {
        let metric_requests = measure_req_attr.to_requests();

        for metric in metric_requests.iter() {
            let metric_var = metric.ident();
            inner = quote! {
                metered::measure! { #metric_var, #inner }
            };
        }
    }

    // Let-bindings to avoid moving issues
    for measure_req_attr in measure_request_attrs.iter() {
        let metric_requests = measure_req_attr.to_requests();

        for metric in metric_requests.iter() {
            let metric_var = syn::Ident::new(&metric.field_name, proc_macro2::Span::call_site());

            inner = quote! {
                let #metric_var = &#registry_expr.#fun_ident.#metric_var;
                #inner
            };
        }

        // // Use debug routine if enabled!
        // if let Some(opt) = metric.debug {
        // }
    }

    // Add final braces
    quote! {
        {
            #inner
        }
    }
}


================================================
FILE: metered-macro/src/metered_opts.rs
================================================
//! The module supporting `#[metered]` options

use syn::{
    parse::{Parse, ParseStream},
    Result,
};

use synattra::{types::KVOption, *};

use std::borrow::Cow;

pub struct Metered<'a> {
    pub registry_ident: &'a syn::Ident,
    pub registry_name: String,
    pub registry_expr: Cow<'a, syn::Expr>,
    pub visibility: Cow<'a, syn::Visibility>,
}

pub struct MeteredKeyValAttribute {
    pub values: syn::punctuated::Punctuated<MeteredOption, Token![,]>,
}

impl MeteredKeyValAttribute {
    fn validate(&self, input: ParseStream<'_>) -> Result<()> {
        self.values
            .iter()
            .filter_map(|opt| {
                if let MeteredOption::Registry(tpe) = opt {
                    Some(&tpe.value)
                } else {
                    None
                }
            })
            .next()
            .ok_or_else(|| input.error("missing `registry` attribute."))?;

        let opt_types: std::collections::HashMap<_, _> = self
            .values
            .iter()
            .map(|opt| (std::mem::discriminant(opt), opt.as_str()))
            .collect();

        for (opt_type, opt_name) in opt_types.iter() {
            let count = self
                .values
                .iter()
                .filter(|&opt| std::mem::discriminant(opt) == *opt_type)
                .count();
            if count > 1 {
                let error = format!("`{}` attribute is defined more than once.", opt_name);
                return Err(input.error(error));
            }
        }

        Ok(())
    }

    pub fn to_metered(&self) -> Metered<'_> {
        let registry_ident = self
            .values
            .iter()
            .filter_map(|opt| {
                if let MeteredOption::Registry(tpe) = opt {
                    Some(&tpe.value)
                } else {
                    None
                }
            })
            .next()
            .expect("There should be a registry! This error cannot happen if the structure has been validated first!");

        let registry_name = registry_ident.to_string();

        let registry_expr = self
            .values
            .iter()
            .filter_map(|opt| {
                if let MeteredOption::RegistryExpr(tpe) = opt {
                    Some(&tpe.value)
                } else {
                    None
                }
            })
            .next()
            .map(Cow::Borrowed)
            .unwrap_or_else(|| Cow::Owned(syn::parse_str::<syn::Expr>("self.metrics").unwrap()));

        let visibility = self
            .values
            .iter()
            .filter_map(|opt| {
                if let MeteredOption::Visibility(tpe) = opt {
                    Some(&tpe.value)
                } else {
                    None
                }
            })
            .next()
            .map(Cow::Borrowed)
            .unwrap_or_else(|| {
                Cow::Owned(syn::parse_str::<syn::Visibility>("pub(crate)").unwrap())
            });
        Metered {
            registry_ident,
            registry_name,
            registry_expr,
            visibility,
        }
    }
}

impl Parse for MeteredKeyValAttribute {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        let this = MeteredKeyValAttribute {
            values: input.parse_terminated(MeteredOption::parse)?,
        };

        this.validate(input)?;

        Ok(this)
    }
}

mod kw {
    syn::custom_keyword!(registry);
    syn::custom_keyword!(registry_expr);
    syn::custom_keyword!(visibility);
}

pub type MeteredRegistryOption = KVOption<kw::registry, syn::Ident>;

pub type MeteredRegistryExprOption = KVOption<kw::registry_expr, syn::Expr>;

pub type MeteredVisibilityOption = KVOption<kw::visibility, syn::Visibility>;

#[allow(clippy::large_enum_variant)]
pub enum MeteredOption {
    Registry(MeteredRegistryOption),
    RegistryExpr(MeteredRegistryExprOption),
    Visibility(MeteredVisibilityOption),
}

impl MeteredOption {
    pub fn as_str(&self) -> &str {
        use syn::token::Token;
        match self {
            MeteredOption::Registry(_) => <kw::registry>::display(),
            MeteredOption::RegistryExpr(_) => <kw::registry_expr>::display(),
            MeteredOption::Visibility(_) => <kw::visibility>::display(),
        }
    }
}

impl Parse for MeteredOption {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        if MeteredRegistryOption::peek(input) {
            Ok(input.parse_as(MeteredOption::Registry)?)
        } else if MeteredRegistryExprOption::peek(input) {
            Ok(input.parse_as(MeteredOption::RegistryExpr)?)
        } else if MeteredVisibilityOption::peek(input) {
            Ok(input.parse_as(MeteredOption::Visibility)?)
        } else {
            let err = format!("invalid metered option: {}", input);
            Err(input.error(err))
        }
    }
}


================================================
FILE: rustfmt-unstable.toml
================================================
edition = "2018"
imports_granularity="Crate"
normalize_comments = true
unstable_features = true
wrap_comments = true

Download .txt
gitextract_mcq7nbdx/

├── .cargo/
│   └── config
├── .gitignore
├── .travis.yml
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── demos/
│   ├── Cargo.toml
│   └── src/
│       ├── baz.rs
│       ├── biz.rs
│       └── main.rs
├── metered/
│   ├── Cargo.toml
│   ├── proptest-regressions/
│   │   └── num_wrapper.txt
│   └── src/
│       ├── atomic.rs
│       ├── clear.rs
│       ├── common/
│       │   ├── error_count.rs
│       │   ├── hit_count.rs
│       │   ├── in_flight.rs
│       │   ├── mod.rs
│       │   ├── none_count.rs
│       │   ├── response_time.rs
│       │   └── throughput/
│       │       ├── atomic_tps.rs
│       │       ├── mod.rs
│       │       └── tx_per_sec.rs
│       ├── hdr_histogram.rs
│       ├── int_counter.rs
│       ├── int_gauge.rs
│       ├── lib.rs
│       ├── metric.rs
│       ├── num_wrapper.rs
│       └── time_source.rs
├── metered-macro/
│   ├── Cargo.toml
│   └── src/
│       ├── error_count.rs
│       ├── error_count_opts.rs
│       ├── lib.rs
│       ├── measure_opts.rs
│       ├── metered.rs
│       └── metered_opts.rs
└── rustfmt-unstable.toml
Download .txt
SYMBOL INDEX (232 symbols across 24 files)

FILE: demos/src/baz.rs
  type LibError (line 8) | pub enum LibError {
  type BazError (line 17) | pub enum BazError {
  type Baz (line 25) | pub struct Baz {
    method bir (line 34) | pub fn bir(&self) {
    method bor (line 41) | pub fn bor(&self) {
    method foo (line 46) | pub fn foo(&self) {
    method bar (line 55) | pub fn bar(&self, should_fail: bool) -> Result<(), &'static str> {
    method baz (line 64) | pub async fn baz(&self, should_fail: bool) -> Result<(), &'static str> {
    method bazium (line 76) | pub fn bazium(
    method bazle (line 93) | pub async fn bazle(&self, should_fail: bool) -> Result<(), BazError> {
    method bad (line 103) | pub unsafe fn bad(&self, v: &[u8]) {
    method bur (line 108) | pub fn bur() {

FILE: demos/src/biz.rs
  type Biz (line 4) | pub struct Biz {
    method biz (line 13) | pub fn biz(&self) {

FILE: demos/src/main.rs
  type TestMetrics (line 10) | struct TestMetrics {
  function test (line 15) | fn test(should_fail: bool, metrics: &TestMetrics) -> Result<(), ()> {
  function test_incr (line 30) | fn test_incr(metrics: &TestMetrics) -> Result<(), ()> {
  function sync_procmacro_demo (line 36) | fn sync_procmacro_demo(baz: &Baz) {
  function async_procmacro_demo (line 43) | async fn async_procmacro_demo(baz: Baz) {
  function simple_api_demo (line 54) | fn simple_api_demo() {
  function test_biz (line 69) | fn test_biz() {
  function do_test_biz (line 78) | fn do_test_biz(biz: &Arc<Biz>) {
  function main (line 98) | fn main() {

FILE: metered-macro/src/error_count.rs
  function error_count (line 6) | pub fn error_count(attrs: TokenStream, item: TokenStream) -> syn::Result...
  type FieldWithNestedAttribute (line 160) | type FieldWithNestedAttribute = Option<(Field, Attribute)>;
  function get_nested_attrs (line 168) | fn get_nested_attrs(input: &mut ItemEnum) -> syn::Result<Vec<(Fields, Fi...

FILE: metered-macro/src/error_count_opts.rs
  type ErrorCountOpts (line 12) | pub struct ErrorCountOpts<'a> {
  type ErrorCountKeyValAttribute (line 18) | pub struct ErrorCountKeyValAttribute {
    method validate (line 23) | fn validate(&self, input: ParseStream<'_>) -> Result<()> {
    method to_error_count_opts (line 57) | pub fn to_error_count_opts(&self) -> ErrorCountOpts<'_> {
  method parse (line 110) | fn parse(input: ParseStream<'_>) -> Result<Self> {
  type ErrorCountNameOption (line 127) | pub type ErrorCountNameOption = KVOption<kw::name, syn::Ident>;
  type ErrorCountVisibilityOption (line 129) | pub type ErrorCountVisibilityOption = KVOption<kw::visibility, syn::Visi...
  type ErrorCountSkipClearedOption (line 131) | pub type ErrorCountSkipClearedOption = KVOption<kw::skip_cleared, syn::L...
  type ErrorCountOption (line 134) | pub enum ErrorCountOption {
    method as_str (line 141) | pub fn as_str(&self) -> &str {
  method parse (line 152) | fn parse(input: ParseStream<'_>) -> Result<Self> {

FILE: metered-macro/src/lib.rs
  function metered (line 87) | pub fn metered(attrs: TokenStream, item: TokenStream) -> TokenStream {
  function error_count (line 151) | pub fn error_count(attrs: TokenStream, item: TokenStream) -> TokenStream {

FILE: metered-macro/src/measure_opts.rs
  type MeasureRequest (line 13) | pub struct MeasureRequest<'a> {
  function ident (line 20) | pub fn ident(&self) -> syn::Ident {
  function type_path (line 24) | pub fn type_path(&self) -> &syn::TypePath {
  type MeasureRequestAttribute (line 29) | pub enum MeasureRequestAttribute {
    method to_requests (line 35) | pub fn to_requests(&self) -> Vec<MeasureRequest<'_>> {
  method parse (line 44) | fn parse(input: ParseStream<'_>) -> Result<Self> {
  type NonEmptyMeasureRequestAttribute (line 55) | pub struct NonEmptyMeasureRequestAttribute {
    method to_requests (line 61) | pub fn to_requests(&self) -> Vec<MeasureRequest<'_>> {
  method parse (line 71) | fn parse(input: ParseStream<'_>) -> Result<Self> {
  type MeasureRequestAttributeInner (line 87) | pub enum MeasureRequestAttributeInner {
    method to_requests (line 93) | pub fn to_requests(&self) -> Vec<MeasureRequest<'_>> {
  method parse (line 102) | fn parse(input: ParseStream<'_>) -> Result<Self> {
  type MeasureRequestTypePathAttribute (line 113) | pub struct MeasureRequestTypePathAttribute {
    method to_requests (line 118) | pub fn to_requests(&self) -> Vec<MeasureRequest<'_>> {
  method parse (line 133) | fn parse(input: ParseStream<'_>) -> Result<Self> {
  type MeasureRequestKeyValAttribute (line 140) | pub struct MeasureRequestKeyValAttribute {
    method validate (line 145) | fn validate(&self, input: ParseStream<'_>) -> Result<()> {
    method to_requests (line 185) | pub fn to_requests(&self) -> Vec<MeasureRequest<'_>> {
  function make_field_name (line 223) | fn make_field_name(type_path: &syn::TypePath) -> String {
  method parse (line 236) | fn parse(input: ParseStream<'_>) -> Result<Self> {
  type MeasureTypeOption (line 251) | pub type MeasureTypeOption = KVOption<syn::Token![type], MultipleVal<syn...
  type MeasureDebugOption (line 252) | pub type MeasureDebugOption = KVOption<kw::debug, InvokePath>;
  type MeasureOptions (line 254) | pub enum MeasureOptions {
    method as_str (line 260) | pub fn as_str(&self) -> &str {
  method parse (line 270) | fn parse(input: ParseStream<'_>) -> Result<Self> {

FILE: metered-macro/src/metered.rs
  function metered (line 11) | pub fn metered(attrs: TokenStream, item: TokenStream) -> syn::Result<Tok...
  type MeteredWeave (line 124) | struct MeteredWeave;
  type MacroAttributes (line 126) | type MacroAttributes = MeteredKeyValAttribute;
  method update_fn_block (line 128) | fn update_fn_block(
  type Type (line 166) | type Type = MeasureRequestAttribute;
  method fn_attr_name (line 169) | fn fn_attr_name() -> &'static str {
  function measure_list (line 174) | fn measure_list(

FILE: metered-macro/src/metered_opts.rs
  type Metered (line 12) | pub struct Metered<'a> {
  type MeteredKeyValAttribute (line 19) | pub struct MeteredKeyValAttribute {
    method validate (line 24) | fn validate(&self, input: ParseStream<'_>) -> Result<()> {
    method to_metered (line 58) | pub fn to_metered(&self) -> Metered<'_> {
  method parse (line 113) | fn parse(input: ParseStream<'_>) -> Result<Self> {
  type MeteredRegistryOption (line 130) | pub type MeteredRegistryOption = KVOption<kw::registry, syn::Ident>;
  type MeteredRegistryExprOption (line 132) | pub type MeteredRegistryExprOption = KVOption<kw::registry_expr, syn::Ex...
  type MeteredVisibilityOption (line 134) | pub type MeteredVisibilityOption = KVOption<kw::visibility, syn::Visibil...
  type MeteredOption (line 137) | pub enum MeteredOption {
    method as_str (line 144) | pub fn as_str(&self) -> &str {
  method parse (line 155) | fn parse(input: ParseStream<'_>) -> Result<Self> {

FILE: metered/src/atomic.rs
  type AtomicInt (line 17) | pub struct AtomicInt<T: Copy> {
  function get (line 24) | pub fn get(&self) -> T {
  method fmt (line 30) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  function test_atomic_wraps (line 96) | fn test_atomic_wraps() {

FILE: metered/src/clear.rs
  type Clear (line 13) | pub trait Clear {
    method clear (line 15) | fn clear(&self);
    method clear (line 19) | fn clear(&self) {
    method clear (line 25) | fn clear(&self) {
  type Clearable (line 32) | pub trait Clearable {
    method is_cleared (line 34) | fn is_cleared(&self) -> bool;

FILE: metered/src/common/error_count.rs
  type ErrorCount (line 21) | pub struct ErrorCount<C: Counter = AtomicInt<u64>>(pub C);
  type E (line 26) | type E = ();
  method enter (line 27) | fn enter(&self) {}
  function on_result (line 31) | fn on_result(&self, _: (), r: &Result<T, E>) -> Advice {
  method clear (line 40) | fn clear(&self) {
  type Target (line 46) | type Target = C;
  method deref (line 48) | fn deref(&self) -> &Self::Target {

FILE: metered/src/common/hit_count.rs
  type HitCount (line 21) | pub struct HitCount<C: Counter = AtomicInt<u64>>(pub C);
  type E (line 26) | type E = ();
  method enter (line 27) | fn enter(&self) -> Self::E {
  method clear (line 35) | fn clear(&self) {
  type Target (line 41) | type Target = C;
  method deref (line 43) | fn deref(&self) -> &Self::Target {

FILE: metered/src/common/in_flight.rs
  type InFlight (line 30) | pub struct InFlight<G: Gauge = AtomicInt<u64>>(pub G);
  type E (line 35) | type E = ();
  method enter (line 36) | fn enter(&self) {
  function leave_scope (line 42) | fn leave_scope(&self, _: ()) -> Advice {
  method clear (line 49) | fn clear(&self) {
  type Target (line 56) | type Target = G;
  method deref (line 58) | fn deref(&self) -> &Self::Target {

FILE: metered/src/common/none_count.rs
  type NoneCount (line 22) | pub struct NoneCount<C: Counter = AtomicInt<u64>>(pub C);
  type E (line 29) | type E = ();
  method enter (line 30) | fn enter(&self) {}
  function on_result (line 34) | fn on_result(&self, _: (), r: &Result<Option<T>, E>) -> Advice {
  function on_result (line 43) | fn on_result(&self, _: (), r: &Option<T>) -> Advice {
  method clear (line 52) | fn clear(&self) {
  type Target (line 58) | type Target = C;
  method deref (line 60) | fn deref(&self) -> &Self::Target {

FILE: metered/src/common/response_time.rs
  type ResponseTime (line 25) | pub struct ResponseTime<H: Histogram = AtomicHdrHistogram, T: Instant = ...
  function with_bound (line 47) | pub fn with_bound(bound: Duration) -> Self {
  method default (line 53) | fn default() -> Self {
  type E (line 64) | type E = T;
  method enter (line 66) | fn enter(&self) -> T {
  function leave_scope (line 72) | fn leave_scope(&self, enter: T) -> Advice {
  method clear (line 80) | fn clear(&self) {
  method serialize (line 86) | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
  method fmt (line 96) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  type Target (line 102) | type Target = H;
  method deref (line 104) | fn deref(&self) -> &Self::Target {

FILE: metered/src/common/throughput/atomic_tps.rs
  type AtomicTxPerSec (line 12) | pub struct AtomicTxPerSec<T: Instant = StdInstant> {
  function histogram (line 19) | pub fn histogram(&self) -> HdrHistogram {
  method on_result (line 26) | fn on_result(&self) {
  method default (line 32) | fn default() -> Self {
  method clear (line 40) | fn clear(&self) {
  method serialize (line 46) | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
  method fmt (line 57) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

FILE: metered/src/common/throughput/mod.rs
  type Throughput (line 30) | pub struct Throughput<T: Instant = StdInstant, P: RecordThroughput = Ato...
  type RecordThroughput (line 36) | pub trait RecordThroughput: Default {
    method on_result (line 38) | fn on_result(&self);
  method default (line 42) | fn default() -> Self {
  type E (line 50) | type E = ();
  method enter (line 52) | fn enter(&self) {}
  method clear (line 56) | fn clear(&self) {
  function leave_scope (line 62) | fn leave_scope(&self, _enter: ()) -> Advice {
  method serialize (line 69) | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
  method fmt (line 79) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  type Target (line 85) | type Target = P;
  method deref (line 87) | fn deref(&self) -> &Self::Target {

FILE: metered/src/common/throughput/tx_per_sec.rs
  type TxPerSec (line 11) | pub struct TxPerSec<T: Instant = StdInstant> {
  method default (line 21) | fn default() -> Self {
  method on_result (line 36) | fn on_result(&self) {
  method clear (line 42) | fn clear(&self) {
  function update (line 49) | fn update(&mut self) {
  function on_result (line 72) | pub(crate) fn on_result(&mut self) {
  function clear (line 77) | pub(crate) fn clear(&mut self) {
  method serialize (line 86) | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
  method fmt (line 96) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

FILE: metered/src/hdr_histogram.rs
  type AtomicHdrHistogram (line 9) | pub struct AtomicHdrHistogram {
    method histogram (line 15) | pub fn histogram(&self) -> HdrHistogram {
  method with_bound (line 21) | fn with_bound(max_bound: u64) -> Self {
  method record (line 27) | fn record(&self, value: u64) {
  method clear (line 33) | fn clear(&self) {
  method serialize (line 39) | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
  method fmt (line 52) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  type HdrHistogram (line 64) | pub struct HdrHistogram {
    method with_bound (line 73) | pub fn with_bound(max_bound: u64) -> Self {
    method bound (line 81) | pub fn bound(&self) -> u64 {
    method record (line 89) | pub fn record(&mut self, value: u64) {
    method record_n (line 98) | pub fn record_n(&mut self, value: u64, count: u64) {
    method clear (line 104) | pub fn clear(&mut self) {
    method len (line 109) | pub fn len(&self) -> u64 {
    method is_empty (line 114) | pub fn is_empty(&self) -> bool {
    method min (line 120) | pub fn min(&self) -> u64 {
    method max (line 127) | pub fn max(&self) -> u64 {
    method mean (line 132) | pub fn mean(&self) -> f64 {
    method stdev (line 138) | pub fn stdev(&self) -> f64 {
    method p90 (line 143) | pub fn p90(&self) -> u64 {
    method p95 (line 148) | pub fn p95(&self) -> u64 {
    method p99 (line 153) | pub fn p99(&self) -> u64 {
    method p999 (line 158) | pub fn p999(&self) -> u64 {
    method p9999 (line 163) | pub fn p9999(&self) -> u64 {
  method serialize (line 169) | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
  type MetricAlias (line 215) | struct MetricAlias<T: Serialize>(&'static str, T);
  method serialize (line 217) | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
  method fmt (line 226) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  method with_bound (line 251) | fn with_bound(max_value: u64) -> Self {
  method record (line 255) | fn record(&self, value: u64) {
  method clear (line 261) | fn clear(&self) {

FILE: metered/src/lib.rs
  function error_variant_serializer (line 214) | pub fn error_variant_serializer<S: serde::Serializer, T: serde::Serialize>(
  function error_variant_serializer_skip_cleared (line 225) | pub fn error_variant_serializer_skip_cleared<
  type ErrorBreakdown (line 241) | pub trait ErrorBreakdown<C: metric::Counter> {
  type ErrorBreakdownIncr (line 248) | pub trait ErrorBreakdownIncr<E> {
    method incr (line 250) | fn incr(&self, e: &E);

FILE: metered/src/metric.rs
  type Metric (line 15) | pub trait Metric<R>: Default + OnResultMut<R> + Clear + Serialize {}
  function on_result (line 19) | pub fn on_result<R, A: Metric<R>>(metric: &A, _enter: <A as Enter>::E, _...
  type ExitGuard (line 23) | pub struct ExitGuard<'a, R, M: Metric<R>> {
  function new (line 32) | pub fn new(metric: &'a M) -> Self {
  function on_result (line 41) | pub fn on_result(mut self, result: &mut R) {
  method drop (line 51) | fn drop(&mut self) {
  type Counter (line 61) | pub trait Counter: Default + Clear + Clearable + Serialize {
    method incr (line 63) | fn incr(&self) {
    method incr_by (line 71) | fn incr_by(&self, count: usize);
  type Gauge (line 75) | pub trait Gauge: Default + Clear + Serialize {
    method incr (line 77) | fn incr(&self) {
    method decr (line 82) | fn decr(&self) {
    method incr_by (line 90) | fn incr_by(&self, count: usize);
    method decr_by (line 96) | fn decr_by(&self, count: usize);
  type Histogram (line 100) | pub trait Histogram: Clear + Serialize {
    method with_bound (line 102) | fn with_bound(max_value: u64) -> Self;
    method record (line 108) | fn record(&self, value: u64);

FILE: metered/src/num_wrapper.rs
  type NumWrapper (line 41) | pub(crate) struct NumWrapper<T>(PhantomData<T>);
  function incr_by (line 107) | fn incr_by(cc: u8, count: usize) -> u8 {
  function incr_by_naive (line 111) | fn incr_by_naive(mut cc: u8, count: usize) -> u8 {
  function decr_by (line 118) | fn decr_by(cc: u8, count: usize) -> u8 {
  function decr_by_naive (line 122) | fn decr_by_naive(mut cc: u8, count: usize) -> u8 {

FILE: metered/src/time_source.rs
  type Instant (line 10) | pub trait Instant {
    method now (line 12) | fn now() -> Self;
    method elapsed_time (line 18) | fn elapsed_time(&self) -> u64;
    method units (line 21) | fn units(duration: Duration) -> u64;
    constant ONE_SEC (line 24) | const ONE_SEC: u64;
    constant ONE_SEC (line 32) | const ONE_SEC: u64 = 1_000;
    method now (line 34) | fn now() -> Self {
    method elapsed_time (line 38) | fn elapsed_time(&self) -> u64 {
    method units (line 44) | fn units(duration: Duration) -> u64 {
    constant ONE_SEC (line 54) | const ONE_SEC: u64 = 1_000_000;
    method now (line 56) | fn now() -> Self {
    method elapsed_time (line 60) | fn elapsed_time(&self) -> u64 {
    method units (line 66) | fn units(duration: Duration) -> u64 {
  type StdInstant (line 30) | pub struct StdInstant(std::time::Instant);
  type StdInstantMicros (line 52) | pub struct StdInstantMicros(std::time::Instant);
Condensed preview — 39 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (131K chars).
[
  {
    "path": ".cargo/config",
    "chars": 318,
    "preview": "[alias]\n# Run against all targets\ncheck-all = \"check --all --all-targets --all-features\"\nclippy-all = \"clippy --all --al"
  },
  {
    "path": ".gitignore",
    "chars": 40,
    "preview": "/target\n**/target\n**/*.rs.bk\nCargo.lock\n"
  },
  {
    "path": ".travis.yml",
    "chars": 240,
    "preview": "language: rust\n\ncache: cargo\n\nrust:\n  - stable\n  - beta\n  - nightly\n\nmatrix:\n  allow_failures:\n    - rust: nightly\n  fas"
  },
  {
    "path": "Cargo.toml",
    "chars": 58,
    "preview": "[workspace]\nmembers = [\n  \"metered\",\n  \"metered-macro\",\n]\n"
  },
  {
    "path": "LICENSE-APACHE",
    "chars": 11322,
    "preview": "       Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org"
  },
  {
    "path": "LICENSE-MIT",
    "chars": 1062,
    "preview": "Copyright (c) 2018-2019 Simon Chemouil\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "README.md",
    "chars": 15593,
    "preview": "# metered-rs\n[![Build Status](https://travis-ci.org/magnet/metered-rs.svg?branch=master)](https://travis-ci.org/magnet/m"
  },
  {
    "path": "demos/Cargo.toml",
    "chars": 656,
    "preview": "[package]\nname = \"metered-demo\"\nversion = \"0.1.0\"\nauthors = [\"Simon Chemouil <simon.chemouil@lambdacube.fr>\"]\nedition = "
  },
  {
    "path": "demos/src/baz.rs",
    "chars": 3098,
    "preview": "#![allow(dead_code)]\n\nuse metered::{metered, ErrorCount, HitCount, InFlight, ResponseTime};\nuse thiserror::Error;\n\n#[met"
  },
  {
    "path": "demos/src/biz.rs",
    "chars": 448,
    "preview": "use metered::{metered, HitCount, Throughput};\n\n#[derive(Default, Debug, serde::Serialize)]\npub struct Biz {\n    pub(crat"
  },
  {
    "path": "demos/src/main.rs",
    "chars": 2627,
    "preview": "use metered::clear::Clear;\nuse metered::*;\nmod baz;\nuse baz::Baz;\nmod biz;\nuse biz::Biz;\nuse std::collections::HashMap;\n"
  },
  {
    "path": "metered/Cargo.toml",
    "chars": 1095,
    "preview": "[package]\nname = \"metered\"\nversion = \"0.9.0\"\nauthors = [\"Simon Chemouil <simon.chemouil@lambdacube.fr>\"]\nlicense = \"Apac"
  },
  {
    "path": "metered/proptest-regressions/num_wrapper.txt",
    "chars": 389,
    "preview": "# Seeds for failure cases proptest has generated in the past. It is\n# automatically read and these particular cases re-r"
  },
  {
    "path": "metered/src/atomic.rs",
    "chars": 2994,
    "preview": "//! A module providing new-type Atomic wrapper that implements Debug &\n//! Serialize.\n\nuse serde::{Serialize, Serializer"
  },
  {
    "path": "metered/src/clear.rs",
    "chars": 957,
    "preview": "//! A module providing a Clear trait which signals metrics to clear their state\n//! if applicable.\n\nuse std::sync::Arc;\n"
  },
  {
    "path": "metered/src/common/error_count.rs",
    "chars": 1272,
    "preview": "//! A module providing the `ErrorCount` metric.\n\nuse crate::{\n    atomic::AtomicInt,\n    clear::Clear,\n    metric::{Coun"
  },
  {
    "path": "metered/src/common/hit_count.rs",
    "chars": 1090,
    "preview": "//! A module providing the `HitCount` metric.\n\nuse crate::{\n    atomic::AtomicInt,\n    clear::Clear,\n    metric::{Counte"
  },
  {
    "path": "metered/src/common/in_flight.rs",
    "chars": 1628,
    "preview": "//! A module providing the `InFlight` metric.\n\nuse crate::{\n    atomic::AtomicInt,\n    clear::Clear,\n    metric::{Gauge,"
  },
  {
    "path": "metered/src/common/mod.rs",
    "chars": 376,
    "preview": "//! A module providing common metrics.\n\nmod error_count;\nmod hit_count;\nmod in_flight;\nmod none_count;\nmod response_time"
  },
  {
    "path": "metered/src/common/none_count.rs",
    "chars": 1645,
    "preview": "//! A module providing the `NoneCount` metric.\n\nuse crate::{\n    atomic::AtomicInt,\n    clear::Clear,\n    metric::{Count"
  },
  {
    "path": "metered/src/common/response_time.rs",
    "chars": 3423,
    "preview": "//! A module providing the `ResponseTime` metric.\n\nuse crate::{\n    clear::Clear,\n    hdr_histogram::AtomicHdrHistogram,"
  },
  {
    "path": "metered/src/common/throughput/atomic_tps.rs",
    "chars": 1600,
    "preview": "use super::{tx_per_sec::TxPerSec, RecordThroughput};\nuse crate::{\n    clear::Clear,\n    hdr_histogram::HdrHistogram,\n   "
  },
  {
    "path": "metered/src/common/throughput/mod.rs",
    "chars": 2596,
    "preview": "//! A module providing the `Throughput` metric.\n\nuse crate::{\n    clear::Clear,\n    metric::Metric,\n    time_source::{In"
  },
  {
    "path": "metered/src/common/throughput/tx_per_sec.rs",
    "chars": 2813,
    "preview": "use super::RecordThroughput;\nuse crate::{\n    clear::Clear,\n    hdr_histogram::HdrHistogram,\n    time_source::{Instant, "
  },
  {
    "path": "metered/src/hdr_histogram.rs",
    "chars": 7946,
    "preview": "//! A module providing thread-safe and unsynchronized implementations for\n//! Histograms, based on HdrHistogram.\n\nuse cr"
  },
  {
    "path": "metered/src/int_counter.rs",
    "chars": 1456,
    "preview": "//! A module providing thread-safe and unsynchronized implementations for\n//! Counters on various unsized integers.\n\nuse"
  },
  {
    "path": "metered/src/int_gauge.rs",
    "chars": 1164,
    "preview": "//! A module providing thread-safe and unsynchronized implementations for Gauges\n//! on various unsized integers.\n\nuse c"
  },
  {
    "path": "metered/src/lib.rs",
    "chars": 9344,
    "preview": "//! # Fast, ergonomic metrics for Rust!\n//!\n//! Metered helps you measure the performance of your programs in production"
  },
  {
    "path": "metered/src/metric.rs",
    "chars": 3399,
    "preview": "//! A module defining the [`Metric`] trait and common metric backends.\n\nuse crate::clear::{Clear, Clearable};\n/// Re-exp"
  },
  {
    "path": "metered/src/num_wrapper.rs",
    "chars": 5346,
    "preview": "use std::marker::PhantomData;\n\n/// Metered metrics wrap when the counters are at capacity instead of\n/// overflowing or "
  },
  {
    "path": "metered/src/time_source.rs",
    "chars": 1964,
    "preview": "//! A module for Time Sources.\n\nuse std::convert::TryFrom;\nuse std::time::Duration;\n\n/// A trait for any time source pro"
  },
  {
    "path": "metered-macro/Cargo.toml",
    "chars": 979,
    "preview": "[package]\nname = \"metered-macro\"\nversion = \"0.9.0\"\nauthors = [\"Simon Chemouil <simon.chemouil@lambdacube.fr>\"]\nlicense ="
  },
  {
    "path": "metered-macro/src/error_count.rs",
    "chars": 7795,
    "preview": "use crate::error_count_opts::ErrorCountKeyValAttribute;\nuse heck::ToSnakeCase;\nuse proc_macro::TokenStream;\nuse syn::{At"
  },
  {
    "path": "metered-macro/src/error_count_opts.rs",
    "chars": 4766,
    "preview": "//! The module supporting `#[error_count]` options\n\nuse syn::{\n    parse::{Parse, ParseStream},\n    Result,\n};\n\nuse syna"
  },
  {
    "path": "metered-macro/src/lib.rs",
    "chars": 4869,
    "preview": "//! Procedural macros for Metered, a metric library for Rust.\n//!\n//! Please check the Metered crate for more documentat"
  },
  {
    "path": "metered-macro/src/measure_opts.rs",
    "chars": 7560,
    "preview": "//! The module supporting `#[measure]` options\n\nuse syn::{\n    parse::{Parse, ParseStream},\n    Result,\n};\n\nuse synattra"
  },
  {
    "path": "metered-macro/src/metered.rs",
    "chars": 6115,
    "preview": "//! The module supporting #[metered]\n\nuse proc_macro::TokenStream;\n\nuse crate::{measure_opts::MeasureRequestAttribute, m"
  },
  {
    "path": "metered-macro/src/metered_opts.rs",
    "chars": 4859,
    "preview": "//! The module supporting `#[metered]` options\n\nuse syn::{\n    parse::{Parse, ParseStream},\n    Result,\n};\n\nuse synattra"
  },
  {
    "path": "rustfmt-unstable.toml",
    "chars": 118,
    "preview": "edition = \"2018\"\nimports_granularity=\"Crate\"\nnormalize_comments = true\nunstable_features = true\nwrap_comments = true\n\n"
  }
]

About this extraction

This page contains the full source code of the magnet/metered-rs GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 39 files (122.1 KB), approximately 31.0k tokens, and a symbol index with 232 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!