зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1436830 - Drop slog dependency. r=rillian,jgraham
MozReview-Commit-ID: A9BZF9VoQuN
This commit is contained in:
Родитель
fdc441f4cb
Коммит
08cd2492a7
|
@ -1 +0,0 @@
|
|||
{"files":{".travis.yml":"5c1a66c2f3f70d7a6fd7ee40b87863d95b78294244cc037453220d64fc431362","CHANGELOG.md":"729d4632f518b0c699d1b947e5d8ddd3fc6a8878bd7796d7b96b2f58772f0478","Cargo.toml":"778cf5a227b5f6a0200d9385d2a8adc59a559a6822ab4d1941348f3eee92d791","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0","README.md":"ea4153526db8a7b7c33fba324fd87f9e43ecac4c973ec1af242c325768c1a4b3","scala-bench/bench.scala":"8f203f98f2c938115247a8ed5ef9d0848fe0f8dca49fc43e2dba88bdd61029e3","src/bin/bench.rs":"7826ed26fcce96f0e2fe3d0b46c36bbfde70168546124018394b1aae8fbf1ec3","src/bin/extra_impls/mod.rs":"b72e67187cbfc1672faacd7d906604f3adc0c7540c781db88c6f4f1726229db9","src/bin/extra_impls/mpsc_queue.rs":"94551cbe0075c40472bae74cb500070c5c621e3690e15c1374b56c5cb7dd6639","src/bin/stress-msq.rs":"f49ba9adb0308013dbd7ed748572659c8b25d045e20609a21ed29ce35784f8f7","src/lib.rs":"b84c7a07bcae8342ce791e42566d103bfc7ac072994a2fe4d6f0b14c8d905f2d","src/mem/cache_padded.rs":"710de7fc76c04bda2e9eafa9f2e9a038fd381330f0e2ac657b56552a9bd9223c","src/mem/epoch/atomic.rs":"ec73c5e271b6b16bc489d3a6b47a48c5ef21cd1d8320d5ed01a6cac271afb42a","src/mem/epoch/garbage.rs":"dd3a3270481da756cf2e8aece5518642059d72492ffbdb107ad9c92d608ed3d3","src/mem/epoch/global.rs":"901df28fdb255cf2466962fa1fcfe3f3006325b94d80a5edb71e3251cecd592e","src/mem/epoch/guard.rs":"75c2a771d88e859f1f53a79a9466ed1e62a6854a1ddca99c6dcaa3d4ca3520e1","src/mem/epoch/local.rs":"d451c2c05fe50e80bdc92313d074b7db13f54d6caa3cf6df6ba5b717566932ae","src/mem/epoch/mod.rs":"a57570492cc2b23b5d6164e0738af5b8d7d65c4b2de08fdfaa2283a47481fce0","src/mem/epoch/participant.rs":"d16e9a81d34f8368340126e9e420bdeec9e661c94aec7a26057be26cad0982df","src/mem/epoch/participants.rs":"c7f4edd7e632130cd149afad8abbeb21888df55b7e4db4206a8840a218bf764d","src/mem/mod.rs":"c60aaeee01ce6abe2418f6f2a3cdd38564a6a46d3c47285d9730a358f52fa6bf","src/scoped.rs":"9ef97832dea5dbdebc88f6c1c8dee5ac5e801f302b70ba17b667214fc3fe57ed","src/sync/arc_cell.rs":"d12dcaca3d59cb0a7c34470dff60c11cb8e25ecde87baf3940bd0747bb107672","src/sync/atomic_option.rs":"dcdfd1080c35d782f041edc7d6c52c1c8fc05f4fe75a9dad261a8982f954ae97","src/sync/chase_lev.rs":"9679cb37bf777466c714e3b8aca7c583638e4534cbb298449130cfa7a07c1d78","src/sync/mod.rs":"35e5f793530e198e891e6ef619da161bbcd31a1de1419dc5b9e9a954d3542c02","src/sync/ms_queue.rs":"cf735b32c12d3227364b2a2abf75a99e5f36f2980b58f34821462cdaf1aac209","src/sync/seg_queue.rs":"e9178f259a0fec71aeb4fb9d5c2bd668eb3dc5f3a3808f167eaae263d76f6646","src/sync/treiber_stack.rs":"60e7f82a42379fbcc2b418b9d50cef98ebc743d9747bf646eb1f3d723189bea4"},"package":"0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"}
|
|
@ -1,36 +0,0 @@
|
|||
language: rust
|
||||
# necessary for `travis-cargo coveralls --no-sudo`
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libcurl4-openssl-dev
|
||||
- libelf-dev
|
||||
- libdw-dev
|
||||
|
||||
# run builds for all the trains (and more)
|
||||
rust:
|
||||
- nightly
|
||||
- beta
|
||||
- stable
|
||||
|
||||
# load travis-cargo
|
||||
before_script:
|
||||
- |
|
||||
pip install 'travis-cargo<0.2' --user &&
|
||||
export PATH=$HOME/.local/bin:$PATH
|
||||
|
||||
# the main build
|
||||
script:
|
||||
- |
|
||||
travis-cargo build &&
|
||||
travis-cargo test &&
|
||||
travis-cargo test -- --release &&
|
||||
travis-cargo run -- --bin bench --release &&
|
||||
travis-cargo --only stable doc
|
||||
env:
|
||||
global:
|
||||
# override the default `--features unstable` used for the nightly branch (optional)
|
||||
- TRAVIS_CARGO_NIGHTLY_FEATURE=nightly
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
|
@ -1,11 +0,0 @@
|
|||
# Version 0.2
|
||||
|
||||
- Changed existing non-blocking `pop` methods to `try_pop`
|
||||
- Added blocking `pop` support to Michael-Scott queue
|
||||
- Added Chase-Lev work-stealing deque
|
||||
|
||||
# Version 0.1
|
||||
|
||||
- Added [epoch-based memory management](http://aturon.github.io/blog/2015/08/27/epoch/)
|
||||
- Added Michael-Scott queue
|
||||
- Added Segmented array queue
|
|
@ -1,15 +0,0 @@
|
|||
[package]
|
||||
name = "crossbeam"
|
||||
version = "0.2.10"
|
||||
authors = ["Aaron Turon <aturon@mozilla.com>"]
|
||||
description = "Support for lock-free data structures, synchronizers, and parallel programming"
|
||||
repository = "https://github.com/aturon/crossbeam"
|
||||
documentation = "http://aturon.github.io/crossbeam-doc/crossbeam/"
|
||||
readme = "README.md"
|
||||
license = "Apache-2.0/MIT"
|
||||
|
||||
[features]
|
||||
nightly = []
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.3"
|
|
@ -1,201 +0,0 @@
|
|||
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 [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
|
@ -1,25 +0,0 @@
|
|||
Copyright (c) 2015 The Rust Project Developers
|
||||
|
||||
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.
|
|
@ -1,38 +0,0 @@
|
|||
# Crossbeam: support for concurrent and parallel programming
|
||||
|
||||
[![Build Status](https://travis-ci.org/aturon/crossbeam.svg?branch=master)](https://travis-ci.org/aturon/crossbeam)
|
||||
|
||||
This crate is an early work in progress. The focus for the moment is
|
||||
concurrency:
|
||||
|
||||
- **Non-blocking data structures**. These data structures allow for high
|
||||
performance, highly-concurrent access, much superior to wrapping with a
|
||||
`Mutex`. Ultimately the goal is to include stacks, queues, deques, bags, sets
|
||||
and maps.
|
||||
|
||||
- **Memory management**. Because non-blocking data structures avoid global
|
||||
synchronization, it is not easy to tell when internal data can be safely
|
||||
freed. The `mem` module provides generic, easy to use, and high-performance APIs
|
||||
for managing memory in these cases.
|
||||
|
||||
- **Synchronization**. The standard library provides a few synchronization
|
||||
primitives (locks, semaphores, barriers, etc) but this crate seeks to expand
|
||||
that set to include more advanced/niche primitives, as well as userspace
|
||||
alternatives.
|
||||
|
||||
- **Scoped thread API**. Finally, the crate provides a "scoped" thread API,
|
||||
making it possible to spawn threads that share stack data with their parents.
|
||||
|
||||
# Usage
|
||||
|
||||
To use Crossbeam, add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
crossbeam = "0.2"
|
||||
```
|
||||
|
||||
For examples of what Crossbeam is capable of, see the
|
||||
[documentation][docs].
|
||||
|
||||
[docs]: http://aturon.github.io/crossbeam-doc/crossbeam/
|
|
@ -1,195 +0,0 @@
|
|||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent._
|
||||
import scala.concurrent.duration._
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import java.util.concurrent.atomic._
|
||||
import java.util.Stack
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
||||
final class MSQueue[A](a: A) {
|
||||
private abstract class Q
|
||||
private final case class Node(data: A, next: AtomicReference[Q] = new AtomicReference(Emp)) extends Q
|
||||
private final case object Emp extends Q
|
||||
private val head = new AtomicReference(Node(a))
|
||||
private val tail = new AtomicReference(head.get())
|
||||
|
||||
def enq(a: A) {
|
||||
val newNode = new Node(a)
|
||||
while (true) {
|
||||
val curTail = tail.get()
|
||||
curTail.next.get()match {
|
||||
case n@Node(_,_) => tail.compareAndSet(curTail, n)
|
||||
case Emp => {
|
||||
if (curTail.next.compareAndSet(Emp, newNode)) {
|
||||
tail.compareAndSet(curTail, newNode)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def deq(): Option[A] = {
|
||||
while (true) {
|
||||
val cur_head = head.get()
|
||||
cur_head.next.get() match {
|
||||
case Emp => return None
|
||||
case n@Node(data, _) => {
|
||||
if (head.compareAndSet(cur_head, n)) {
|
||||
return Some(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
abstract class MyBool
|
||||
final case class MyTrue() extends MyBool
|
||||
final case class MyFalse() extends MyBool
|
||||
|
||||
object Bench {
|
||||
def time(block: => Unit): Long = {
|
||||
val t0 = System.nanoTime()
|
||||
val result = block // call-by-name
|
||||
val t1 = System.nanoTime()
|
||||
t1 - t0
|
||||
}
|
||||
|
||||
def do_linked(threads: Int, count: Int) {
|
||||
val q: ConcurrentLinkedQueue[MyBool] = new ConcurrentLinkedQueue();
|
||||
|
||||
val t = time {
|
||||
var s = new Stack[Future[Unit]]
|
||||
for (i <- 1 to threads) {
|
||||
s.push(Future {
|
||||
for (i <- 1 to count+1) {
|
||||
//if (i % 100000 == 0) { println(q.size()) }
|
||||
q.offer(MyTrue())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var rn = 0
|
||||
while (rn < count) {
|
||||
if (q.poll() != null) {
|
||||
rn += 1
|
||||
}
|
||||
}
|
||||
|
||||
while (!s.empty()) {
|
||||
Await.ready(s.pop(), Duration.Inf)
|
||||
}
|
||||
}
|
||||
|
||||
println("Linked: " + t / (count * threads))
|
||||
}
|
||||
|
||||
def do_linked_mpmc(threads: Int, count: Int) {
|
||||
val q = new ConcurrentLinkedQueue[MyBool];
|
||||
val prod = new AtomicInteger();
|
||||
|
||||
val t = time {
|
||||
var s = new Stack[Future[Unit]]
|
||||
for (i <- 1 to threads) {
|
||||
s.push(Future {
|
||||
for (i <- 1 to count+1) {
|
||||
q.offer(MyTrue())
|
||||
//if (i % 100000 == 0) { println(q.size()) }
|
||||
}
|
||||
if (prod.incrementAndGet() == threads) {
|
||||
for (i <- 0 to threads) { q.offer(MyFalse()) }
|
||||
}
|
||||
})
|
||||
s.push(Future {
|
||||
var done = false;
|
||||
while (!done) {
|
||||
q.poll() match {
|
||||
case MyFalse() => done = true
|
||||
case _ => {}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
while (!s.empty()) {
|
||||
Await.ready(s.pop(), Duration.Inf)
|
||||
}
|
||||
}
|
||||
|
||||
println("Linked mpmc: " + t / (count * threads) + " (" + t / 1000000000 + ")")
|
||||
}
|
||||
|
||||
|
||||
def do_msq(threads: Int, count: Int) {
|
||||
val q = new MSQueue[Int](0);
|
||||
|
||||
val t = time {
|
||||
var s = new Stack[Future[Unit]]
|
||||
for (i <- 1 to threads) {
|
||||
s.push(Future { for (i <- 1 to count+1) { q.enq(i) } })
|
||||
}
|
||||
|
||||
var rn = 0
|
||||
while (rn < count) {
|
||||
if (q.deq() != None) {
|
||||
rn += 1
|
||||
}
|
||||
}
|
||||
|
||||
while (!s.empty()) {
|
||||
Await.ready(s.pop(), Duration.Inf)
|
||||
}
|
||||
}
|
||||
|
||||
println("MSQ: " + t / (count * threads) + " (" + t / 1000000000 + ")")
|
||||
}
|
||||
|
||||
def do_msq_mpmc(threads: Int, count: Int) {
|
||||
val q = new MSQueue[Boolean](true);
|
||||
val prod = new AtomicInteger();
|
||||
|
||||
val t = time {
|
||||
var s = new Stack[Future[Unit]]
|
||||
for (i <- 1 to threads) {
|
||||
s.push(Future {
|
||||
for (i <- 1 to count+1) { q.enq(true) }
|
||||
if (prod.incrementAndGet() == threads) {
|
||||
for (i <- 1 to threads) { q.enq(false) }
|
||||
}
|
||||
})
|
||||
s.push(Future {
|
||||
var done = false;
|
||||
while (!done) {
|
||||
q.deq() match {
|
||||
case Some(false) => done = true
|
||||
case _ => {}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
while (!s.empty()) {
|
||||
Await.ready(s.pop(), Duration.Inf)
|
||||
}
|
||||
}
|
||||
|
||||
println("MSQ mpmc: " + t / (count * threads) + " (" + t / 1000000000 + ")")
|
||||
}
|
||||
|
||||
def main(args: Array[String]) {
|
||||
do_linked(2, 1000000)
|
||||
do_linked(2, 10000000)
|
||||
|
||||
do_msq(2, 1000000)
|
||||
do_msq(2, 10000000)
|
||||
|
||||
do_linked_mpmc(2, 1000000)
|
||||
do_linked_mpmc(2, 10000000)
|
||||
|
||||
do_msq_mpmc(2, 1000000)
|
||||
do_msq_mpmc(2, 10000000)
|
||||
}
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
extern crate crossbeam;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::time::Duration;
|
||||
|
||||
use crossbeam::scope;
|
||||
use crossbeam::sync::MsQueue;
|
||||
use crossbeam::sync::SegQueue;
|
||||
|
||||
use extra_impls::mpsc_queue::Queue as MpscQueue;
|
||||
|
||||
mod extra_impls;
|
||||
|
||||
const COUNT: u64 = 10000000;
|
||||
const THREADS: u64 = 2;
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
fn time<F: FnOnce()>(f: F) -> Duration {
|
||||
let start = ::std::time::Instant::now();
|
||||
f();
|
||||
start.elapsed()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
fn time<F: FnOnce()>(_f: F) -> Duration {
|
||||
Duration::new(0, 0)
|
||||
}
|
||||
|
||||
fn nanos(d: Duration) -> f64 {
|
||||
d.as_secs() as f64 * 1000000000f64 + (d.subsec_nanos() as f64)
|
||||
}
|
||||
|
||||
trait Queue<T> {
|
||||
fn push(&self, T);
|
||||
fn try_pop(&self) -> Option<T>;
|
||||
}
|
||||
|
||||
impl<T> Queue<T> for MsQueue<T> {
|
||||
fn push(&self, t: T) { self.push(t) }
|
||||
fn try_pop(&self) -> Option<T> { self.try_pop() }
|
||||
}
|
||||
|
||||
impl<T> Queue<T> for SegQueue<T> {
|
||||
fn push(&self, t: T) { self.push(t) }
|
||||
fn try_pop(&self) -> Option<T> { self.try_pop() }
|
||||
}
|
||||
|
||||
impl<T> Queue<T> for MpscQueue<T> {
|
||||
fn push(&self, t: T) { self.push(t) }
|
||||
fn try_pop(&self) -> Option<T> {
|
||||
use extra_impls::mpsc_queue::*;
|
||||
|
||||
loop {
|
||||
match self.pop() {
|
||||
Data(t) => return Some(t),
|
||||
Empty => return None,
|
||||
Inconsistent => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Queue<T> for Mutex<VecDeque<T>> {
|
||||
fn push(&self, t: T) { self.lock().unwrap().push_back(t) }
|
||||
fn try_pop(&self) -> Option<T> { self.lock().unwrap().pop_front() }
|
||||
}
|
||||
|
||||
fn bench_queue_mpsc<Q: Queue<u64> + Sync>(q: Q) -> f64 {
|
||||
let d = time(|| {
|
||||
scope(|scope| {
|
||||
for _i in 0..THREADS {
|
||||
let qr = &q;
|
||||
scope.spawn(move || {
|
||||
for x in 0..COUNT {
|
||||
let _ = qr.push(x);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let mut count = 0;
|
||||
while count < COUNT*THREADS {
|
||||
if q.try_pop().is_some() {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
nanos(d) / ((COUNT * THREADS) as f64)
|
||||
}
|
||||
|
||||
fn bench_queue_mpmc<Q: Queue<bool> + Sync>(q: Q) -> f64 {
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering::Relaxed;
|
||||
|
||||
let prod_count = AtomicUsize::new(0);
|
||||
|
||||
let d = time(|| {
|
||||
scope(|scope| {
|
||||
for _i in 0..THREADS {
|
||||
let qr = &q;
|
||||
let pcr = &prod_count;
|
||||
scope.spawn(move || {
|
||||
for _x in 0..COUNT {
|
||||
qr.push(true);
|
||||
}
|
||||
if pcr.fetch_add(1, Relaxed) == (THREADS as usize) - 1 {
|
||||
for _x in 0..THREADS {
|
||||
qr.push(false)
|
||||
}
|
||||
}
|
||||
});
|
||||
scope.spawn(move || {
|
||||
loop {
|
||||
if let Some(false) = qr.try_pop() { break }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
nanos(d) / ((COUNT * THREADS) as f64)
|
||||
}
|
||||
|
||||
fn bench_chan_mpsc() -> f64 {
|
||||
let (tx, rx) = channel();
|
||||
|
||||
let d = time(|| {
|
||||
scope(|scope| {
|
||||
for _i in 0..THREADS {
|
||||
let my_tx = tx.clone();
|
||||
|
||||
scope.spawn(move || {
|
||||
for x in 0..COUNT {
|
||||
let _ = my_tx.send(x);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for _i in 0..COUNT*THREADS {
|
||||
let _ = rx.recv().unwrap();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
nanos(d) / ((COUNT * THREADS) as f64)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("MSQ mpsc: {}", bench_queue_mpsc(MsQueue::new()));
|
||||
println!("chan mpsc: {}", bench_chan_mpsc());
|
||||
println!("mpsc mpsc: {}", bench_queue_mpsc(MpscQueue::new()));
|
||||
println!("Seg mpsc: {}", bench_queue_mpsc(SegQueue::new()));
|
||||
|
||||
println!("MSQ mpmc: {}", bench_queue_mpmc(MsQueue::new()));
|
||||
println!("Seg mpmc: {}", bench_queue_mpmc(SegQueue::new()));
|
||||
|
||||
// println!("queue_mpsc: {}", bench_queue_mpsc());
|
||||
// println!("queue_mpmc: {}", bench_queue_mpmc());
|
||||
// println!("mutex_mpmc: {}", bench_mutex_mpmc());
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
pub mod mpsc_queue;
|
|
@ -1,155 +0,0 @@
|
|||
/* Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are
|
||||
* those of the authors and should not be interpreted as representing official
|
||||
* policies, either expressed or implied, of Dmitry Vyukov.
|
||||
*/
|
||||
|
||||
//! A mostly lock-free multi-producer, single consumer queue.
|
||||
//!
|
||||
//! This module contains an implementation of a concurrent MPSC queue. This
|
||||
//! queue can be used to share data between threads, and is also used as the
|
||||
//! building block of channels in rust.
|
||||
//!
|
||||
//! Note that the current implementation of this queue has a caveat of the `pop`
|
||||
//! method, and see the method for more information about it. Due to this
|
||||
//! caveat, this queue may not be appropriate for all use-cases.
|
||||
|
||||
// http://www.1024cores.net/home/lock-free-algorithms
|
||||
// /queues/non-intrusive-mpsc-node-based-queue
|
||||
|
||||
pub use self::PopResult::*;
|
||||
|
||||
use std::fmt;
|
||||
use std::ptr;
|
||||
use std::cell::UnsafeCell;
|
||||
|
||||
use std::sync::atomic::{AtomicPtr, Ordering};
|
||||
|
||||
/// A result of the `pop` function.
|
||||
#[derive(Debug)]
|
||||
pub enum PopResult<T> {
|
||||
/// Some data has been popped
|
||||
Data(T),
|
||||
/// The queue is empty
|
||||
Empty,
|
||||
/// The queue is in an inconsistent state. Popping data should succeed, but
|
||||
/// some pushers have yet to make enough progress in order allow a pop to
|
||||
/// succeed. It is recommended that a pop() occur "in the near future" in
|
||||
/// order to see if the sender has made progress or not
|
||||
Inconsistent,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Node<T> {
|
||||
next: AtomicPtr<Node<T>>,
|
||||
value: Option<T>,
|
||||
}
|
||||
|
||||
/// The multi-producer single-consumer structure. This is not cloneable, but it
|
||||
/// may be safely shared so long as it is guaranteed that there is only one
|
||||
/// popper at a time (many pushers are allowed).
|
||||
pub struct Queue<T> {
|
||||
head: AtomicPtr<Node<T>>,
|
||||
tail: UnsafeCell<*mut Node<T>>,
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for Queue<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Queue {{ ... }}")
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for Queue<T> { }
|
||||
unsafe impl<T: Send> Sync for Queue<T> { }
|
||||
|
||||
impl<T> Node<T> {
|
||||
unsafe fn new(v: Option<T>) -> *mut Node<T> {
|
||||
Box::into_raw(Box::new(Node {
|
||||
next: AtomicPtr::new(ptr::null_mut()),
|
||||
value: v,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Queue<T> {
|
||||
/// Creates a new queue that is safe to share among multiple producers and
|
||||
/// one consumer.
|
||||
pub fn new() -> Queue<T> {
|
||||
let stub = unsafe { Node::new(None) };
|
||||
Queue {
|
||||
head: AtomicPtr::new(stub),
|
||||
tail: UnsafeCell::new(stub),
|
||||
}
|
||||
}
|
||||
|
||||
/// Pushes a new value onto this queue.
|
||||
pub fn push(&self, t: T) {
|
||||
unsafe {
|
||||
let n = Node::new(Some(t));
|
||||
let prev = self.head.swap(n, Ordering::AcqRel);
|
||||
(*prev).next.store(n, Ordering::Release);
|
||||
}
|
||||
}
|
||||
|
||||
/// Pops some data from this queue.
|
||||
///
|
||||
/// Note that the current implementation means that this function cannot
|
||||
/// return `Option<T>`. It is possible for this queue to be in an
|
||||
/// inconsistent state where many pushes have succeeded and completely
|
||||
/// finished, but pops cannot return `Some(t)`. This inconsistent state
|
||||
/// happens when a pusher is pre-empted at an inopportune moment.
|
||||
///
|
||||
/// This inconsistent state means that this queue does indeed have data, but
|
||||
/// it does not currently have access to it at this time.
|
||||
pub fn pop(&self) -> PopResult<T> {
|
||||
unsafe {
|
||||
let tail = *self.tail.get();
|
||||
let next = (*tail).next.load(Ordering::Acquire);
|
||||
|
||||
if !next.is_null() {
|
||||
*self.tail.get() = next;
|
||||
assert!((*tail).value.is_none());
|
||||
assert!((*next).value.is_some());
|
||||
let ret = (*next).value.take().unwrap();
|
||||
let _ = Box::from_raw(tail);
|
||||
return Data(ret);
|
||||
}
|
||||
|
||||
if self.head.load(Ordering::Acquire) == tail {Empty} else {Inconsistent}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for Queue<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let mut cur = *self.tail.get();
|
||||
while !cur.is_null() {
|
||||
let next = (*cur).next.load(Ordering::Relaxed);
|
||||
let _ = Box::from_raw(cur);
|
||||
cur = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
extern crate crossbeam;
|
||||
|
||||
use crossbeam::sync::MsQueue;
|
||||
use crossbeam::scope;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
const DUP: usize = 4;
|
||||
const THREADS: u32 = 2;
|
||||
const COUNT: u64 = 100000;
|
||||
|
||||
fn main() {
|
||||
scope(|s| {
|
||||
for _i in 0..DUP {
|
||||
let q = Arc::new(MsQueue::new());
|
||||
let qs = q.clone();
|
||||
|
||||
s.spawn(move || {
|
||||
for i in 1..COUNT { qs.push(i) }
|
||||
});
|
||||
|
||||
for _i in 0..THREADS {
|
||||
let qr = q.clone();
|
||||
s.spawn(move || {
|
||||
let mut cur: u64 = 0;
|
||||
for _j in 0..COUNT {
|
||||
if let Some(new) = qr.try_pop() {
|
||||
assert!(new > cur);
|
||||
cur = new;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
//! Support for concurrent and parallel programming.
|
||||
//!
|
||||
//! This crate is an early work in progress. The focus for the moment is
|
||||
//! concurrency:
|
||||
//!
|
||||
//! - **Non-blocking data structures**. These data structures allow for high
|
||||
//! performance, highly-concurrent access, much superior to wrapping with a
|
||||
//! `Mutex`. Ultimately the goal is to include stacks, queues, deques, bags,
|
||||
//! sets and maps. These live in the `sync` module.
|
||||
//!
|
||||
//! - **Memory management**. Because non-blocking data structures avoid global
|
||||
//! synchronization, it is not easy to tell when internal data can be safely
|
||||
//! freed. The `mem` module provides generic, easy to use, and high-performance
|
||||
//! APIs for managing memory in these cases. These live in the `mem` module.
|
||||
//!
|
||||
//! - **Synchronization**. The standard library provides a few synchronization
|
||||
//! primitives (locks, semaphores, barriers, etc) but this crate seeks to expand
|
||||
//! that set to include more advanced/niche primitives, as well as userspace
|
||||
//! alternatives. These live in the `sync` module.
|
||||
//!
|
||||
//! - **Scoped thread API**. Finally, the crate provides a "scoped" thread API,
|
||||
//! making it possible to spawn threads that share stack data with their
|
||||
//! parents. This functionality is exported at the top-level.
|
||||
|
||||
//#![deny(missing_docs)]
|
||||
|
||||
#![cfg_attr(feature = "nightly",
|
||||
feature(const_fn, repr_simd, optin_builtin_traits))]
|
||||
|
||||
use std::thread;
|
||||
|
||||
pub use scoped::{scope, Scope, ScopedJoinHandle};
|
||||
|
||||
pub mod mem;
|
||||
pub mod sync;
|
||||
mod scoped;
|
||||
|
||||
#[doc(hidden)]
|
||||
trait FnBox {
|
||||
fn call_box(self: Box<Self>);
|
||||
}
|
||||
|
||||
impl<F: FnOnce()> FnBox for F {
|
||||
fn call_box(self: Box<Self>) { (*self)() }
|
||||
}
|
||||
|
||||
/// Like `std::thread::spawn`, but without the closure bounds.
|
||||
pub unsafe fn spawn_unsafe<'a, F>(f: F) -> thread::JoinHandle<()> where F: FnOnce() + Send + 'a {
|
||||
use std::mem;
|
||||
|
||||
let closure: Box<FnBox + 'a> = Box::new(f);
|
||||
let closure: Box<FnBox + Send> = mem::transmute(closure);
|
||||
thread::spawn(move || closure.call_box())
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
use std::marker;
|
||||
use std::cell::UnsafeCell;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
// For now, treat this as an arch-independent constant.
|
||||
const CACHE_LINE: usize = 32;
|
||||
|
||||
#[cfg_attr(feature = "nightly",
|
||||
repr(simd))]
|
||||
#[derive(Debug)]
|
||||
struct Padding(u64, u64, u64, u64);
|
||||
|
||||
/// Pad `T` to the length of a cacheline.
|
||||
///
|
||||
/// Sometimes concurrent programming requires a piece of data to be padded out
|
||||
/// to the size of a cacheline to avoid "false sharing": cachelines being
|
||||
/// invalidated due to unrelated concurrent activity. Use the `CachePadded` type
|
||||
/// when you want to *avoid* cache locality.
|
||||
///
|
||||
/// At the moment, cache lines are assumed to be 32 * sizeof(usize) on all
|
||||
/// architectures.
|
||||
///
|
||||
/// **Warning**: the wrapped data is never dropped; move out using `ptr::read`
|
||||
/// if you need to run dtors.
|
||||
pub struct CachePadded<T> {
|
||||
data: UnsafeCell<[usize; CACHE_LINE]>,
|
||||
_marker: ([Padding; 0], marker::PhantomData<T>),
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for CachePadded<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "CachePadded {{ ... }}")
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for CachePadded<T> {}
|
||||
unsafe impl<T: Sync> Sync for CachePadded<T> {}
|
||||
|
||||
/// Types for which mem::zeroed() is safe.
|
||||
///
|
||||
/// If a type `T: ZerosValid`, then a sequence of zeros the size of `T` must be
|
||||
/// a valid member of the type `T`.
|
||||
pub unsafe trait ZerosValid {}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
unsafe impl ZerosValid for .. {}
|
||||
|
||||
macro_rules! zeros_valid { ($( $T:ty )*) => ($(
|
||||
unsafe impl ZerosValid for $T {}
|
||||
)*)}
|
||||
|
||||
zeros_valid!(u8 u16 u32 u64 usize);
|
||||
zeros_valid!(i8 i16 i32 i64 isize);
|
||||
|
||||
unsafe impl ZerosValid for ::std::sync::atomic::AtomicUsize {}
|
||||
unsafe impl<T> ZerosValid for ::std::sync::atomic::AtomicPtr<T> {}
|
||||
|
||||
impl<T: ZerosValid> CachePadded<T> {
|
||||
/// A const fn equivalent to mem::zeroed().
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
pub fn zeroed() -> CachePadded<T> {
|
||||
CachePadded {
|
||||
data: UnsafeCell::new(([0; CACHE_LINE])),
|
||||
_marker: ([], marker::PhantomData),
|
||||
}
|
||||
}
|
||||
|
||||
/// A const fn equivalent to mem::zeroed().
|
||||
#[cfg(feature = "nightly")]
|
||||
pub const fn zeroed() -> CachePadded<T> {
|
||||
CachePadded {
|
||||
data: UnsafeCell::new(([0; CACHE_LINE])),
|
||||
_marker: ([], marker::PhantomData),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Assert that the size and alignment of `T` are consistent with `CachePadded<T>`.
|
||||
fn assert_valid<T>() {
|
||||
assert!(mem::size_of::<T>() <= mem::size_of::<CachePadded<T>>());
|
||||
assert!(mem::align_of::<T>() <= mem::align_of::<CachePadded<T>>());
|
||||
}
|
||||
|
||||
impl<T> CachePadded<T> {
|
||||
/// Wrap `t` with cacheline padding.
|
||||
///
|
||||
/// **Warning**: the wrapped data is never dropped; move out using
|
||||
/// `ptr:read` if you need to run dtors.
|
||||
pub fn new(t: T) -> CachePadded<T> {
|
||||
assert_valid::<T>();
|
||||
let ret = CachePadded {
|
||||
data: UnsafeCell::new(([0; CACHE_LINE])),
|
||||
_marker: ([], marker::PhantomData),
|
||||
};
|
||||
unsafe {
|
||||
let p: *mut T = mem::transmute(&ret.data);
|
||||
ptr::write(p, t);
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for CachePadded<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
assert_valid::<T>();
|
||||
unsafe { mem::transmute(&self.data) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for CachePadded<T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
assert_valid::<T>();
|
||||
unsafe { mem::transmute(&mut self.data) }
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: support Drop by pulling out a version usable for statics
|
||||
/*
|
||||
impl<T> Drop for CachePadded<T> {
|
||||
fn drop(&mut self) {
|
||||
assert_valid::<T>();
|
||||
let p: *mut T = mem::transmute(&self.data);
|
||||
mem::drop(ptr::read(p));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn cache_padded_store_u64() {
|
||||
let x: CachePadded<u64> = CachePadded::new(17);
|
||||
assert_eq!(*x, 17);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cache_padded_store_pair() {
|
||||
let x: CachePadded<(u64, u64)> = CachePadded::new((17, 37));
|
||||
assert_eq!(x.0, 17);
|
||||
assert_eq!(x.1, 37);
|
||||
}
|
||||
}
|
|
@ -1,181 +0,0 @@
|
|||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::sync::atomic::{self, Ordering};
|
||||
|
||||
use super::{Owned, Shared, Guard};
|
||||
|
||||
/// Like `std::sync::atomic::AtomicPtr`.
|
||||
///
|
||||
/// Provides atomic access to a (nullable) pointer of type `T`, interfacing with
|
||||
/// the `Owned` and `Shared` types.
|
||||
#[derive(Debug)]
|
||||
pub struct Atomic<T> {
|
||||
ptr: atomic::AtomicPtr<T>,
|
||||
_marker: PhantomData<*const ()>,
|
||||
}
|
||||
|
||||
unsafe impl<T: Sync> Send for Atomic<T> {}
|
||||
unsafe impl<T: Sync> Sync for Atomic<T> {}
|
||||
|
||||
fn opt_shared_into_raw<T>(val: Option<Shared<T>>) -> *mut T {
|
||||
val.map(|p| p.as_raw()).unwrap_or(ptr::null_mut())
|
||||
}
|
||||
|
||||
fn opt_owned_as_raw<T>(val: &Option<Owned<T>>) -> *mut T {
|
||||
val.as_ref().map(Owned::as_raw).unwrap_or(ptr::null_mut())
|
||||
}
|
||||
|
||||
fn opt_owned_into_raw<T>(val: Option<Owned<T>>) -> *mut T {
|
||||
let ptr = val.as_ref().map(Owned::as_raw).unwrap_or(ptr::null_mut());
|
||||
mem::forget(val);
|
||||
ptr
|
||||
}
|
||||
|
||||
impl<T> Atomic<T> {
|
||||
/// Create a new, null atomic pointer.
|
||||
#[cfg(feature = "nightly")]
|
||||
pub const fn null() -> Atomic<T> {
|
||||
Atomic {
|
||||
ptr: atomic::AtomicPtr::new(0 as *mut _),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
pub fn null() -> Atomic<T> {
|
||||
Atomic {
|
||||
ptr: atomic::AtomicPtr::new(0 as *mut _),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new atomic pointer
|
||||
pub fn new(data: T) -> Atomic<T> {
|
||||
Atomic {
|
||||
ptr: atomic::AtomicPtr::new(Box::into_raw(Box::new(data))),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
/// Do an atomic load with the given memory ordering.
|
||||
///
|
||||
/// In order to perform the load, we must pass in a borrow of a
|
||||
/// `Guard`. This is a way of guaranteeing that the thread has pinned the
|
||||
/// epoch for the entire lifetime `'a`. In return, you get an optional
|
||||
/// `Shared` pointer back (`None` if the `Atomic` is currently null), with
|
||||
/// lifetime tied to the guard.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `ord` is `Release` or `AcqRel`.
|
||||
pub fn load<'a>(&self, ord: Ordering, _: &'a Guard) -> Option<Shared<'a, T>> {
|
||||
unsafe { Shared::from_raw(self.ptr.load(ord)) }
|
||||
}
|
||||
|
||||
/// Do an atomic store with the given memory ordering.
|
||||
///
|
||||
/// Transfers ownership of the given `Owned` pointer, if any. Since no
|
||||
/// lifetime information is acquired, no `Guard` value is needed.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `ord` is `Acquire` or `AcqRel`.
|
||||
pub fn store(&self, val: Option<Owned<T>>, ord: Ordering) {
|
||||
self.ptr.store(opt_owned_into_raw(val), ord)
|
||||
}
|
||||
|
||||
/// Do an atomic store with the given memory ordering, immediately yielding
|
||||
/// a shared reference to the pointer that was stored.
|
||||
///
|
||||
/// Transfers ownership of the given `Owned` pointer, yielding a `Shared`
|
||||
/// reference to it. Since the reference is valid only for the curent epoch,
|
||||
/// it's lifetime is tied to a `Guard` value.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `ord` is `Acquire` or `AcqRel`.
|
||||
pub fn store_and_ref<'a>(&self, val: Owned<T>, ord: Ordering, _: &'a Guard)
|
||||
-> Shared<'a, T>
|
||||
{
|
||||
unsafe {
|
||||
let shared = Shared::from_owned(val);
|
||||
self.store_shared(Some(shared), ord);
|
||||
shared
|
||||
}
|
||||
}
|
||||
|
||||
/// Do an atomic store of a `Shared` pointer with the given memory ordering.
|
||||
///
|
||||
/// This operation does not require a guard, because it does not yield any
|
||||
/// new information about the lifetime of a pointer.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `ord` is `Acquire` or `AcqRel`.
|
||||
pub fn store_shared(&self, val: Option<Shared<T>>, ord: Ordering) {
|
||||
self.ptr.store(opt_shared_into_raw(val), ord)
|
||||
}
|
||||
|
||||
/// Do a compare-and-set from a `Shared` to an `Owned` pointer with the
|
||||
/// given memory ordering.
|
||||
///
|
||||
/// As with `store`, this operation does not require a guard; it produces no new
|
||||
/// lifetime information. The `Result` indicates whether the CAS succeeded; if
|
||||
/// not, ownership of the `new` pointer is returned to the caller.
|
||||
pub fn cas(&self, old: Option<Shared<T>>, new: Option<Owned<T>>, ord: Ordering)
|
||||
-> Result<(), Option<Owned<T>>>
|
||||
{
|
||||
if self.ptr.compare_and_swap(opt_shared_into_raw(old),
|
||||
opt_owned_as_raw(&new),
|
||||
ord) == opt_shared_into_raw(old)
|
||||
{
|
||||
mem::forget(new);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(new)
|
||||
}
|
||||
}
|
||||
|
||||
/// Do a compare-and-set from a `Shared` to an `Owned` pointer with the
|
||||
/// given memory ordering, immediatley acquiring a new `Shared` reference to
|
||||
/// the previously-owned pointer if successful.
|
||||
///
|
||||
/// This operation is analogous to `store_and_ref`.
|
||||
pub fn cas_and_ref<'a>(&self, old: Option<Shared<T>>, new: Owned<T>,
|
||||
ord: Ordering, _: &'a Guard)
|
||||
-> Result<Shared<'a, T>, Owned<T>>
|
||||
{
|
||||
if self.ptr.compare_and_swap(opt_shared_into_raw(old), new.as_raw(), ord)
|
||||
== opt_shared_into_raw(old)
|
||||
{
|
||||
Ok(unsafe { Shared::from_owned(new) })
|
||||
} else {
|
||||
Err(new)
|
||||
}
|
||||
}
|
||||
|
||||
/// Do a compare-and-set from a `Shared` to another `Shared` pointer with
|
||||
/// the given memory ordering.
|
||||
///
|
||||
/// The boolean return value is `true` when the CAS is successful.
|
||||
pub fn cas_shared(&self, old: Option<Shared<T>>, new: Option<Shared<T>>, ord: Ordering)
|
||||
-> bool
|
||||
{
|
||||
self.ptr.compare_and_swap(opt_shared_into_raw(old),
|
||||
opt_shared_into_raw(new),
|
||||
ord) == opt_shared_into_raw(old)
|
||||
}
|
||||
|
||||
/// Do an atomic swap with an `Owned` pointer with the given memory ordering.
|
||||
pub fn swap<'a>(&self, new: Option<Owned<T>>, ord: Ordering, _: &'a Guard)
|
||||
-> Option<Shared<'a, T>> {
|
||||
unsafe { Shared::from_raw(self.ptr.swap(opt_owned_into_raw(new), ord)) }
|
||||
}
|
||||
|
||||
/// Do an atomic swap with a `Shared` pointer with the given memory ordering.
|
||||
pub fn swap_shared<'a>(&self, new: Option<Shared<T>>, ord: Ordering, _: &'a Guard)
|
||||
-> Option<Shared<'a, T>> {
|
||||
unsafe { Shared::from_raw(self.ptr.swap(opt_shared_into_raw(new), ord)) }
|
||||
}
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
// Data structures for storing garbage to be freed later (once the
|
||||
// epochs have sufficiently advanced).
|
||||
//
|
||||
// In general, we try to manage the garbage thread locally whenever
|
||||
// possible. Each thread keep track of three bags of garbage. But if a
|
||||
// thread is exiting, these bags must be moved into the global garbage
|
||||
// bags.
|
||||
|
||||
use std::ptr;
|
||||
use std::mem;
|
||||
use std::sync::atomic::AtomicPtr;
|
||||
use std::sync::atomic::Ordering::{Relaxed, Release, Acquire};
|
||||
|
||||
use mem::ZerosValid;
|
||||
|
||||
/// One item of garbage.
|
||||
///
|
||||
/// Stores enough information to do a deallocation.
|
||||
#[derive(Debug)]
|
||||
struct Item {
|
||||
ptr: *mut u8,
|
||||
free: unsafe fn(*mut u8),
|
||||
}
|
||||
|
||||
/// A single, thread-local bag of garbage.
|
||||
#[derive(Debug)]
|
||||
pub struct Bag(Vec<Item>);
|
||||
|
||||
impl Bag {
|
||||
fn new() -> Bag {
|
||||
Bag(vec![])
|
||||
}
|
||||
|
||||
fn insert<T>(&mut self, elem: *mut T) {
|
||||
let size = mem::size_of::<T>();
|
||||
if size > 0 {
|
||||
self.0.push(Item {
|
||||
ptr: elem as *mut u8,
|
||||
free: free::<T>,
|
||||
})
|
||||
}
|
||||
unsafe fn free<T>(t: *mut u8) {
|
||||
drop(Vec::from_raw_parts(t as *mut T, 0, 1));
|
||||
}
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
/// Deallocate all garbage in the bag
|
||||
pub unsafe fn collect(&mut self) {
|
||||
let mut data = mem::replace(&mut self.0, Vec::new());
|
||||
for item in data.iter() {
|
||||
(item.free)(item.ptr);
|
||||
}
|
||||
data.truncate(0);
|
||||
self.0 = data;
|
||||
}
|
||||
}
|
||||
|
||||
// needed because the bags store raw pointers.
|
||||
unsafe impl Send for Bag {}
|
||||
unsafe impl Sync for Bag {}
|
||||
|
||||
/// A thread-local set of garbage bags.
|
||||
#[derive(Debug)]
|
||||
pub struct Local {
|
||||
/// Garbage added at least one epoch behind the current local epoch
|
||||
pub old: Bag,
|
||||
/// Garbage added in the current local epoch or earlier
|
||||
pub cur: Bag,
|
||||
/// Garbage added in the current *global* epoch
|
||||
pub new: Bag,
|
||||
}
|
||||
|
||||
impl Local {
|
||||
pub fn new() -> Local {
|
||||
Local {
|
||||
old: Bag::new(),
|
||||
cur: Bag::new(),
|
||||
new: Bag::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert<T>(&mut self, elem: *mut T) {
|
||||
self.new.insert(elem)
|
||||
}
|
||||
|
||||
/// Collect one epoch of garbage, rotating the local garbage bags.
|
||||
pub unsafe fn collect(&mut self) {
|
||||
let ret = self.old.collect();
|
||||
mem::swap(&mut self.old, &mut self.cur);
|
||||
mem::swap(&mut self.cur, &mut self.new);
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
self.old.len() + self.cur.len() + self.new.len()
|
||||
}
|
||||
}
|
||||
|
||||
/// A concurrent garbage bag, currently based on Treiber's stack.
|
||||
///
|
||||
/// The elements are themselves owned `Bag`s.
|
||||
#[derive(Debug)]
|
||||
pub struct ConcBag {
|
||||
head: AtomicPtr<Node>,
|
||||
}
|
||||
|
||||
unsafe impl ZerosValid for ConcBag {}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Node {
|
||||
data: Bag,
|
||||
next: AtomicPtr<Node>,
|
||||
}
|
||||
|
||||
impl ConcBag {
|
||||
pub fn insert(&self, t: Bag){
|
||||
let n = Box::into_raw(Box::new(
|
||||
Node { data: t, next: AtomicPtr::new(ptr::null_mut()) }));
|
||||
loop {
|
||||
let head = self.head.load(Acquire);
|
||||
unsafe { (*n).next.store(head, Relaxed) };
|
||||
if self.head.compare_and_swap(head, n, Release) == head { break }
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn collect(&self) {
|
||||
// check to avoid xchg instruction
|
||||
// when no garbage exists
|
||||
let mut head = self.head.load(Relaxed);
|
||||
if head != ptr::null_mut() {
|
||||
head = self.head.swap(ptr::null_mut(), Acquire);
|
||||
|
||||
while head != ptr::null_mut() {
|
||||
let mut n = Box::from_raw(head);
|
||||
n.data.collect();
|
||||
head = n.next.load(Relaxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
// Definition of global epoch state. The `get` function is the way to
|
||||
// access this data externally (until const fn is stabilized...).
|
||||
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
|
||||
use mem::CachePadded;
|
||||
use mem::epoch::garbage;
|
||||
use mem::epoch::participants::Participants;
|
||||
|
||||
/// Global epoch state
|
||||
#[derive(Debug)]
|
||||
pub struct EpochState {
|
||||
/// Current global epoch
|
||||
pub epoch: CachePadded<AtomicUsize>,
|
||||
|
||||
// FIXME: move this into the `garbage` module, rationalize API
|
||||
/// Global garbage bags
|
||||
pub garbage: [CachePadded<garbage::ConcBag>; 3],
|
||||
|
||||
/// Participant list
|
||||
pub participants: Participants,
|
||||
}
|
||||
|
||||
unsafe impl Send for EpochState {}
|
||||
unsafe impl Sync for EpochState {}
|
||||
|
||||
pub use self::imp::get;
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
mod imp {
|
||||
use std::mem;
|
||||
use std::sync::atomic::{self, AtomicUsize};
|
||||
use std::sync::atomic::Ordering::Relaxed;
|
||||
|
||||
use super::EpochState;
|
||||
use mem::CachePadded;
|
||||
use mem::epoch::participants::Participants;
|
||||
|
||||
impl EpochState {
|
||||
fn new() -> EpochState {
|
||||
EpochState {
|
||||
epoch: CachePadded::zeroed(),
|
||||
garbage: [CachePadded::zeroed(),
|
||||
CachePadded::zeroed(),
|
||||
CachePadded::zeroed()],
|
||||
participants: Participants::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static EPOCH: AtomicUsize = atomic::ATOMIC_USIZE_INIT;
|
||||
|
||||
pub fn get() -> &'static EpochState {
|
||||
let mut addr = EPOCH.load(Relaxed);
|
||||
|
||||
if addr == 0 {
|
||||
let boxed = Box::new(EpochState::new());
|
||||
let raw = Box::into_raw(boxed);
|
||||
|
||||
addr = EPOCH.compare_and_swap(0, raw as usize, Relaxed);
|
||||
if addr != 0 {
|
||||
let boxed = unsafe { Box::from_raw(raw) };
|
||||
mem::drop(boxed);
|
||||
} else {
|
||||
addr = raw as usize;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
&*(addr as *mut EpochState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
mod imp {
|
||||
use super::EpochState;
|
||||
use mem::CachePadded;
|
||||
use mem::epoch::participants::Participants;
|
||||
|
||||
impl EpochState {
|
||||
const fn new() -> EpochState {
|
||||
EpochState {
|
||||
epoch: CachePadded::zeroed(),
|
||||
garbage: [CachePadded::zeroed(),
|
||||
CachePadded::zeroed(),
|
||||
CachePadded::zeroed()],
|
||||
participants: Participants::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static EPOCH: EpochState = EpochState::new();
|
||||
pub fn get() -> &'static EpochState { &EPOCH }
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
use std::marker;
|
||||
|
||||
use super::{local, Shared};
|
||||
|
||||
/// An RAII-style guard for pinning the current epoch.
|
||||
///
|
||||
/// A guard must be acquired before most operations on an `Atomic` pointer. On
|
||||
/// destruction, it unpins the epoch.
|
||||
#[must_use]
|
||||
#[derive(Debug)]
|
||||
pub struct Guard {
|
||||
_marker: marker::PhantomData<*mut ()>, // !Send and !Sync
|
||||
}
|
||||
|
||||
/// Pin the current epoch.
|
||||
///
|
||||
/// Threads generally pin before interacting with a lock-free data
|
||||
/// structure. Pinning requires a full memory barrier, so is somewhat
|
||||
/// expensive. It is rentrant -- you can safely acquire nested guards, and only
|
||||
/// the first guard requires a barrier. Thus, in cases where you expect to
|
||||
/// perform several lock-free operations in quick succession, you may consider
|
||||
/// pinning around the entire set of operations.
|
||||
pub fn pin() -> Guard {
|
||||
local::with_participant(|p| {
|
||||
p.enter();
|
||||
|
||||
let g = Guard {
|
||||
_marker: marker::PhantomData,
|
||||
};
|
||||
|
||||
if p.should_gc() {
|
||||
p.try_collect(&g);
|
||||
}
|
||||
|
||||
g
|
||||
})
|
||||
}
|
||||
|
||||
impl Guard {
|
||||
/// Assert that the value is no longer reachable from a lock-free data
|
||||
/// structure and should be collected when sufficient epochs have passed.
|
||||
pub unsafe fn unlinked<T>(&self, val: Shared<T>) {
|
||||
local::with_participant(|p| p.reclaim(val.as_raw()))
|
||||
}
|
||||
|
||||
/// Move the thread-local garbage into the global set of garbage.
|
||||
pub fn migrate_garbage(&self) {
|
||||
local::with_participant(|p| p.migrate_garbage())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Guard {
|
||||
fn drop(&mut self) {
|
||||
local::with_participant(|p| p.exit());
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
// Manage the thread-local state, providing access to a `Participant` record.
|
||||
|
||||
use std::sync::atomic::Ordering::Relaxed;
|
||||
|
||||
use mem::epoch::participant::Participant;
|
||||
use mem::epoch::global;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct LocalEpoch {
|
||||
participant: *const Participant,
|
||||
}
|
||||
|
||||
impl LocalEpoch {
|
||||
fn new() -> LocalEpoch {
|
||||
LocalEpoch { participant: global::get().participants.enroll() }
|
||||
}
|
||||
|
||||
fn get(&self) -> &Participant {
|
||||
unsafe { &*self.participant }
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: avoid leaking when all threads have exited
|
||||
impl Drop for LocalEpoch {
|
||||
fn drop(&mut self) {
|
||||
let p = self.get();
|
||||
p.enter();
|
||||
p.migrate_garbage();
|
||||
p.exit();
|
||||
p.active.store(false, Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
thread_local!(static LOCAL_EPOCH: LocalEpoch = LocalEpoch::new() );
|
||||
|
||||
pub fn with_participant<F, T>(f: F) -> T where F: FnOnce(&Participant) -> T {
|
||||
LOCAL_EPOCH.with(|e| f(e.get()))
|
||||
}
|
|
@ -1,265 +0,0 @@
|
|||
//! Epoch-based memory management
|
||||
//!
|
||||
//! This module provides fast, easy to use memory management for lock free data
|
||||
//! structures. It's inspired by [Keir Fraser's *epoch-based
|
||||
//! reclamation*](https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-579.pdf).
|
||||
//!
|
||||
//! The basic problem this is solving is the fact that when one thread has
|
||||
//! removed a node from a data structure, other threads may still have pointers
|
||||
//! to that node (in the form of snapshots that will be validated through things
|
||||
//! like compare-and-swap), so the memory cannot be immediately freed. Put differently:
|
||||
//!
|
||||
//! 1. There are two sources of reachability at play -- the data structure, and
|
||||
//! the snapshots in threads accessing it. Before we delete a node, we need to know
|
||||
//! that it cannot be reached in either of these ways.
|
||||
//!
|
||||
//! 2. Once a node has been unliked from the data structure, no *new* snapshots
|
||||
//! reaching it will be created.
|
||||
//!
|
||||
//! Using the epoch scheme is fairly straightforward, and does not require
|
||||
//! understanding any of the implementation details:
|
||||
//!
|
||||
//! - When operating on a shared data structure, a thread must "pin the current
|
||||
//! epoch", which is done by calling `pin()`. This function returns a `Guard`
|
||||
//! which unpins the epoch when destroyed.
|
||||
//!
|
||||
//! - When the thread subsequently reads from a lock-free data structure, the
|
||||
//! pointers it extracts act like references with lifetime tied to the
|
||||
//! `Guard`. This allows threads to safely read from snapshotted data, being
|
||||
//! guaranteed that the data will remain allocated until they exit the epoch.
|
||||
//!
|
||||
//! To put the `Guard` to use, Crossbeam provides a set of three pointer types meant to work together:
|
||||
//!
|
||||
//! - `Owned<T>`, akin to `Box<T>`, which points to uniquely-owned data that has
|
||||
//! not yet been published in a concurrent data structure.
|
||||
//!
|
||||
//! - `Shared<'a, T>`, akin to `&'a T`, which points to shared data that may or may
|
||||
//! not be reachable from a data structure, but it guaranteed not to be freed
|
||||
//! during lifetime `'a`.
|
||||
//!
|
||||
//! - `Atomic<T>`, akin to `std::sync::atomic::AtomicPtr`, which provides atomic
|
||||
//! updates to a pointer using the `Owned` and `Shared` types, and connects them
|
||||
//! to a `Guard`.
|
||||
//!
|
||||
//! Each of these types provides further documentation on usage.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! use std::sync::atomic::Ordering::{Acquire, Release, Relaxed};
|
||||
//! use std::ptr;
|
||||
//!
|
||||
//! use crossbeam::mem::epoch::{self, Atomic, Owned};
|
||||
//!
|
||||
//! struct TreiberStack<T> {
|
||||
//! head: Atomic<Node<T>>,
|
||||
//! }
|
||||
//!
|
||||
//! struct Node<T> {
|
||||
//! data: T,
|
||||
//! next: Atomic<Node<T>>,
|
||||
//! }
|
||||
//!
|
||||
//! impl<T> TreiberStack<T> {
|
||||
//! fn new() -> TreiberStack<T> {
|
||||
//! TreiberStack {
|
||||
//! head: Atomic::null()
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! fn push(&self, t: T) {
|
||||
//! // allocate the node via Owned
|
||||
//! let mut n = Owned::new(Node {
|
||||
//! data: t,
|
||||
//! next: Atomic::null(),
|
||||
//! });
|
||||
//!
|
||||
//! // become active
|
||||
//! let guard = epoch::pin();
|
||||
//!
|
||||
//! loop {
|
||||
//! // snapshot current head
|
||||
//! let head = self.head.load(Relaxed, &guard);
|
||||
//!
|
||||
//! // update `next` pointer with snapshot
|
||||
//! n.next.store_shared(head, Relaxed);
|
||||
//!
|
||||
//! // if snapshot is still good, link in the new node
|
||||
//! match self.head.cas_and_ref(head, n, Release, &guard) {
|
||||
//! Ok(_) => return,
|
||||
//! Err(owned) => n = owned,
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! fn pop(&self) -> Option<T> {
|
||||
//! // become active
|
||||
//! let guard = epoch::pin();
|
||||
//!
|
||||
//! loop {
|
||||
//! // take a snapshot
|
||||
//! match self.head.load(Acquire, &guard) {
|
||||
//! // the stack is non-empty
|
||||
//! Some(head) => {
|
||||
//! // read through the snapshot, *safely*!
|
||||
//! let next = head.next.load(Relaxed, &guard);
|
||||
//!
|
||||
//! // if snapshot is still good, update from `head` to `next`
|
||||
//! if self.head.cas_shared(Some(head), next, Release) {
|
||||
//! unsafe {
|
||||
//! // mark the node as unlinked
|
||||
//! guard.unlinked(head);
|
||||
//!
|
||||
//! // extract out the data from the now-unlinked node
|
||||
//! return Some(ptr::read(&(*head).data))
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! // we observed the stack empty
|
||||
//! None => return None
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
// FIXME: document implementation details
|
||||
|
||||
mod atomic;
|
||||
mod garbage;
|
||||
mod global;
|
||||
mod guard;
|
||||
mod local;
|
||||
mod participant;
|
||||
mod participants;
|
||||
|
||||
pub use self::atomic::Atomic;
|
||||
pub use self::guard::{pin, Guard};
|
||||
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::ptr;
|
||||
use std::mem;
|
||||
|
||||
/// Like `Box<T>`: an owned, heap-allocated data value of type `T`.
|
||||
#[derive(Debug)]
|
||||
pub struct Owned<T> {
|
||||
data: Box<T>,
|
||||
}
|
||||
|
||||
impl<T> Owned<T> {
|
||||
/// Move `t` to a new heap allocation.
|
||||
pub fn new(t: T) -> Owned<T> {
|
||||
Owned { data: Box::new(t) }
|
||||
}
|
||||
|
||||
fn as_raw(&self) -> *mut T {
|
||||
self.deref() as *const _ as *mut _
|
||||
}
|
||||
|
||||
/// Move data out of the owned box, deallocating the box.
|
||||
pub fn into_inner(self) -> T {
|
||||
*self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for Owned<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for Owned<T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
&mut self.data
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
/// Like `&'a T`: a shared reference valid for lifetime `'a`.
|
||||
#[derive(Debug)]
|
||||
pub struct Shared<'a, T: 'a> {
|
||||
data: &'a T,
|
||||
}
|
||||
|
||||
impl<'a, T> Copy for Shared<'a, T> {}
|
||||
impl<'a, T> Clone for Shared<'a, T> {
|
||||
fn clone(&self) -> Shared<'a, T> {
|
||||
Shared { data: self.data }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Deref for Shared<'a, T> {
|
||||
type Target = &'a T;
|
||||
fn deref(&self) -> &&'a T {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Shared<'a, T> {
|
||||
unsafe fn from_raw(raw: *mut T) -> Option<Shared<'a, T>> {
|
||||
if raw == ptr::null_mut() { None }
|
||||
else {
|
||||
Some(Shared {
|
||||
data: mem::transmute::<*mut T, &T>(raw)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn from_ref(r: &T) -> Shared<'a, T> {
|
||||
Shared { data: mem::transmute(r) }
|
||||
}
|
||||
|
||||
unsafe fn from_owned(owned: Owned<T>) -> Shared<'a, T> {
|
||||
let ret = Shared::from_ref(owned.deref());
|
||||
mem::forget(owned);
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn as_raw(&self) -> *mut T {
|
||||
self.data as *const _ as *mut _
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::sync::atomic::Ordering;
|
||||
use super::*;
|
||||
use mem::epoch;
|
||||
|
||||
#[test]
|
||||
fn test_no_drop() {
|
||||
static mut DROPS: i32 = 0;
|
||||
struct Test;
|
||||
impl Drop for Test {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DROPS += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
let g = pin();
|
||||
|
||||
let x = Atomic::null();
|
||||
x.store(Some(Owned::new(Test)), Ordering::Relaxed);
|
||||
x.store_and_ref(Owned::new(Test), Ordering::Relaxed, &g);
|
||||
let y = x.load(Ordering::Relaxed, &g);
|
||||
let z = x.cas_and_ref(y, Owned::new(Test), Ordering::Relaxed, &g).ok();
|
||||
let _ = x.cas(z, Some(Owned::new(Test)), Ordering::Relaxed);
|
||||
x.swap(Some(Owned::new(Test)), Ordering::Relaxed, &g);
|
||||
|
||||
unsafe {
|
||||
assert_eq!(DROPS, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new() {
|
||||
let guard = epoch::pin();
|
||||
let my_atomic = Atomic::new(42);
|
||||
|
||||
assert_eq!(**my_atomic.load(Ordering::Relaxed, &guard).unwrap(), 42);
|
||||
}
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
// Manages a single participant in the epoch scheme. This is where all
|
||||
// of the actual epoch management logic happens!
|
||||
|
||||
use std::mem;
|
||||
use std::cell::UnsafeCell;
|
||||
use std::fmt;
|
||||
use std::sync::atomic::{self, AtomicUsize, AtomicBool};
|
||||
use std::sync::atomic::Ordering::{Relaxed, Acquire, Release, SeqCst};
|
||||
|
||||
use mem::epoch::{Atomic, Guard, garbage, global};
|
||||
use mem::epoch::participants::ParticipantNode;
|
||||
|
||||
/// Thread-local data for epoch participation.
|
||||
pub struct Participant {
|
||||
/// The local epoch.
|
||||
epoch: AtomicUsize,
|
||||
|
||||
/// Number of pending uses of `epoch::pin()`; keeping a count allows for
|
||||
/// reentrant use of epoch management.
|
||||
in_critical: AtomicUsize,
|
||||
|
||||
/// Thread-local garbage tracking
|
||||
garbage: UnsafeCell<garbage::Local>,
|
||||
|
||||
/// Is the thread still active? Becomes `false` when the thread exits. This
|
||||
/// is ultimately used to free `Participant` records.
|
||||
pub active: AtomicBool,
|
||||
|
||||
/// The participant list is coded intrusively; here's the `next` pointer.
|
||||
pub next: Atomic<ParticipantNode>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Participant {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Participant {{ ... }}")
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for Participant {}
|
||||
|
||||
const GC_THRESH: usize = 32;
|
||||
|
||||
impl Participant {
|
||||
pub fn new() -> Participant {
|
||||
Participant {
|
||||
epoch: AtomicUsize::new(0),
|
||||
in_critical: AtomicUsize::new(0),
|
||||
active: AtomicBool::new(true),
|
||||
garbage: UnsafeCell::new(garbage::Local::new()),
|
||||
next: Atomic::null(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enter a critical section.
|
||||
///
|
||||
/// This method is reentrant, allowing for nested critical sections.
|
||||
///
|
||||
/// Returns `true` is this is the first entry on the stack (as opposed to a
|
||||
/// re-entrant call).
|
||||
pub fn enter(&self) -> bool {
|
||||
let new_count = self.in_critical.load(Relaxed) + 1;
|
||||
self.in_critical.store(new_count, Relaxed);
|
||||
if new_count > 1 { return false }
|
||||
|
||||
atomic::fence(SeqCst);
|
||||
|
||||
let global_epoch = global::get().epoch.load(Relaxed);
|
||||
if global_epoch != self.epoch.load(Relaxed) {
|
||||
self.epoch.store(global_epoch, Relaxed);
|
||||
unsafe { (*self.garbage.get()).collect(); }
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Exit the current (nested) critical section.
|
||||
pub fn exit(&self) {
|
||||
let new_count = self.in_critical.load(Relaxed) - 1;
|
||||
self.in_critical.store(
|
||||
new_count,
|
||||
if new_count > 0 { Relaxed } else { Release });
|
||||
}
|
||||
|
||||
/// Begin the reclamation process for a piece of data.
|
||||
pub unsafe fn reclaim<T>(&self, data: *mut T) {
|
||||
(*self.garbage.get()).insert(data);
|
||||
}
|
||||
|
||||
/// Attempt to collect garbage by moving the global epoch forward.
|
||||
///
|
||||
/// Returns `true` on success.
|
||||
pub fn try_collect(&self, guard: &Guard) -> bool {
|
||||
let cur_epoch = global::get().epoch.load(SeqCst);
|
||||
|
||||
for p in global::get().participants.iter(guard) {
|
||||
if p.in_critical.load(Relaxed) > 0 && p.epoch.load(Relaxed) != cur_epoch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
let new_epoch = cur_epoch.wrapping_add(1);
|
||||
atomic::fence(Acquire);
|
||||
if global::get().epoch.compare_and_swap(cur_epoch, new_epoch, SeqCst) != cur_epoch {
|
||||
return false
|
||||
}
|
||||
|
||||
unsafe {
|
||||
(*self.garbage.get()).collect();
|
||||
global::get().garbage[new_epoch.wrapping_add(1) % 3].collect();
|
||||
}
|
||||
self.epoch.store(new_epoch, Release);
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Move the current thread-local garbage into the global garbage bags.
|
||||
pub fn migrate_garbage(&self) {
|
||||
let cur_epoch = self.epoch.load(Relaxed);
|
||||
let local = unsafe { mem::replace(&mut *self.garbage.get(), garbage::Local::new()) };
|
||||
global::get().garbage[cur_epoch.wrapping_sub(1) % 3].insert(local.old);
|
||||
global::get().garbage[cur_epoch % 3].insert(local.cur);
|
||||
global::get().garbage[global::get().epoch.load(Relaxed) % 3].insert(local.new);
|
||||
}
|
||||
|
||||
/// How much garbage is this participant currently storing?
|
||||
pub fn garbage_size(&self) -> usize {
|
||||
unsafe { (*self.garbage.get()).size() }
|
||||
}
|
||||
/// Is this participant past its local GC threshhold?
|
||||
pub fn should_gc(&self) -> bool {
|
||||
self.garbage_size() >= GC_THRESH
|
||||
}
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
// Manages the global participant list, which is an intrustive list in
|
||||
// which items are lazily removed on traversal (after being
|
||||
// "logically" deleted by becoming inactive.)
|
||||
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::atomic::Ordering::{Relaxed, Acquire, Release};
|
||||
|
||||
use mem::epoch::{Atomic, Owned, Guard};
|
||||
use mem::epoch::participant::Participant;
|
||||
use mem::CachePadded;
|
||||
|
||||
/// Global, threadsafe list of threads participating in epoch management.
|
||||
#[derive(Debug)]
|
||||
pub struct Participants {
|
||||
head: Atomic<ParticipantNode>
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParticipantNode(CachePadded<Participant>);
|
||||
|
||||
impl ParticipantNode {
|
||||
pub fn new() -> ParticipantNode {
|
||||
ParticipantNode(CachePadded::new(Participant::new()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ParticipantNode {
|
||||
type Target = Participant;
|
||||
fn deref(&self) -> &Participant {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for ParticipantNode {
|
||||
fn deref_mut(&mut self) -> &mut Participant {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Participants {
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
pub fn new() -> Participants {
|
||||
Participants { head: Atomic::null() }
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
pub const fn new() -> Participants {
|
||||
Participants { head: Atomic::null() }
|
||||
}
|
||||
|
||||
/// Enroll a new thread in epoch management by adding a new `Particpant`
|
||||
/// record to the global list.
|
||||
pub fn enroll(&self) -> *const Participant {
|
||||
let mut participant = Owned::new(ParticipantNode::new());
|
||||
|
||||
// we ultimately use epoch tracking to free Participant nodes, but we
|
||||
// can't actually enter an epoch here, so fake it; we know the node
|
||||
// can't be removed until marked inactive anyway.
|
||||
let fake_guard = ();
|
||||
let g: &'static Guard = unsafe { mem::transmute(&fake_guard) };
|
||||
loop {
|
||||
let head = self.head.load(Relaxed, g);
|
||||
participant.next.store_shared(head, Relaxed);
|
||||
match self.head.cas_and_ref(head, participant, Release, g) {
|
||||
Ok(shared) => {
|
||||
let shared: &Participant = &shared;
|
||||
return shared;
|
||||
}
|
||||
Err(owned) => {
|
||||
participant = owned;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter<'a>(&'a self, g: &'a Guard) -> Iter<'a> {
|
||||
Iter {
|
||||
guard: g,
|
||||
next: &self.head,
|
||||
needs_acq: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Iter<'a> {
|
||||
// pin to an epoch so that we can free inactive nodes
|
||||
guard: &'a Guard,
|
||||
next: &'a Atomic<ParticipantNode>,
|
||||
|
||||
// an Acquire read is needed only for the first read, due to release
|
||||
// sequences
|
||||
needs_acq: bool,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Iter<'a> {
|
||||
type Item = &'a Participant;
|
||||
fn next(&mut self) -> Option<&'a Participant> {
|
||||
let mut cur = if self.needs_acq {
|
||||
self.needs_acq = false;
|
||||
self.next.load(Acquire, self.guard)
|
||||
} else {
|
||||
self.next.load(Relaxed, self.guard)
|
||||
};
|
||||
|
||||
while let Some(n) = cur {
|
||||
// attempt to clean up inactive nodes
|
||||
if !n.active.load(Relaxed) {
|
||||
cur = n.next.load(Relaxed, self.guard);
|
||||
// TODO: actually reclaim inactive participants!
|
||||
} else {
|
||||
self.next = &n.next;
|
||||
return Some(&n)
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
//! Memory management for concurrent data structures
|
||||
//!
|
||||
//! At the moment, the only memory management scheme is epoch-based reclamation,
|
||||
//! found in the `epoch` submodule.
|
||||
|
||||
pub use self::cache_padded::{CachePadded, ZerosValid};
|
||||
|
||||
pub mod epoch;
|
||||
mod cache_padded;
|
|
@ -1,275 +0,0 @@
|
|||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
use {spawn_unsafe, FnBox};
|
||||
use sync::AtomicOption;
|
||||
|
||||
pub struct Scope<'a> {
|
||||
dtors: RefCell<Option<DtorChain<'a>>>
|
||||
}
|
||||
|
||||
struct DtorChain<'a> {
|
||||
dtor: Box<FnBox + 'a>,
|
||||
next: Option<Box<DtorChain<'a>>>
|
||||
}
|
||||
|
||||
enum JoinState {
|
||||
Running(thread::JoinHandle<()>),
|
||||
Joined,
|
||||
}
|
||||
|
||||
impl JoinState {
|
||||
fn join(&mut self) {
|
||||
let mut state = JoinState::Joined;
|
||||
mem::swap(self, &mut state);
|
||||
if let JoinState::Running(handle) = state {
|
||||
let res = handle.join();
|
||||
|
||||
if !thread::panicking() { res.unwrap(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A handle to a scoped thread
|
||||
pub struct ScopedJoinHandle<T> {
|
||||
inner: Rc<RefCell<JoinState>>,
|
||||
packet: Arc<AtomicOption<T>>,
|
||||
thread: thread::Thread,
|
||||
}
|
||||
|
||||
/// Create a new `scope`, for deferred destructors.
|
||||
///
|
||||
/// Scopes, in particular, support [*scoped thread spawning*](struct.Scope.html#method.spawn).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Creating and using a scope:
|
||||
///
|
||||
/// ```
|
||||
/// crossbeam::scope(|scope| {
|
||||
/// scope.defer(|| println!("Exiting scope"));
|
||||
/// scope.spawn(|| println!("Running child thread in scope"))
|
||||
/// });
|
||||
/// // Prints messages in the reverse order written
|
||||
/// ```
|
||||
pub fn scope<'a, F, R>(f: F) -> R where F: FnOnce(&Scope<'a>) -> R {
|
||||
let mut scope = Scope { dtors: RefCell::new(None) };
|
||||
let ret = f(&scope);
|
||||
scope.drop_all();
|
||||
ret
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for Scope<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Scope {{ ... }}")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for ScopedJoinHandle<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "ScopedJoinHandle {{ ... }}")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Scope<'a> {
|
||||
// This method is carefully written in a transactional style, so
|
||||
// that it can be called directly and, if any dtor panics, can be
|
||||
// resumed in the unwinding this causes. By initially running the
|
||||
// method outside of any destructor, we avoid any leakage problems
|
||||
// due to @rust-lang/rust#14875.
|
||||
fn drop_all(&mut self) {
|
||||
loop {
|
||||
// use a separate scope to ensure that the RefCell borrow
|
||||
// is relinquishe before running `dtor`
|
||||
let dtor = {
|
||||
let mut dtors = self.dtors.borrow_mut();
|
||||
if let Some(mut node) = dtors.take() {
|
||||
*dtors = node.next.take().map(|b| *b);
|
||||
node.dtor
|
||||
} else {
|
||||
return
|
||||
}
|
||||
};
|
||||
dtor.call_box()
|
||||
}
|
||||
}
|
||||
|
||||
/// Schedule code to be executed when exiting the scope.
|
||||
///
|
||||
/// This is akin to having a destructor on the stack, except that it is
|
||||
/// *guaranteed* to be run.
|
||||
pub fn defer<F>(&self, f: F) where F: FnOnce() + 'a {
|
||||
let mut dtors = self.dtors.borrow_mut();
|
||||
*dtors = Some(DtorChain {
|
||||
dtor: Box::new(f),
|
||||
next: dtors.take().map(Box::new)
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a scoped thread.
|
||||
///
|
||||
/// `spawn` is similar to the [`spawn`][spawn] function in Rust's standard library. The
|
||||
/// difference is that this thread is scoped, meaning that it's guaranteed to terminate
|
||||
/// before the current stack frame goes away, allowing you to reference the parent stack frame
|
||||
/// directly. This is ensured by having the parent thread join on the child thread before the
|
||||
/// scope exits.
|
||||
///
|
||||
/// [spawn]: http://doc.rust-lang.org/std/thread/fn.spawn.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// A basic scoped thread:
|
||||
///
|
||||
/// ```
|
||||
/// crossbeam::scope(|scope| {
|
||||
/// scope.spawn(|| {
|
||||
/// println!("Hello from a scoped thread!");
|
||||
/// });
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// When writing concurrent Rust programs, you'll sometimes see a pattern like this, using
|
||||
/// [`std::thread::spawn`][spawn]:
|
||||
///
|
||||
/// ```ignore
|
||||
/// let array = [1, 2, 3];
|
||||
/// let mut guards = vec![];
|
||||
///
|
||||
/// for i in &array {
|
||||
/// let guard = std::thread::spawn(move || {
|
||||
/// println!("element: {}", i);
|
||||
/// });
|
||||
///
|
||||
/// guards.push(guard);
|
||||
/// }
|
||||
///
|
||||
/// for guard in guards {
|
||||
/// guard.join().unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The basic pattern is:
|
||||
///
|
||||
/// 1. Iterate over some collection.
|
||||
/// 2. Spin up a thread to operate on each part of the collection.
|
||||
/// 3. Join all the threads.
|
||||
///
|
||||
/// However, this code actually gives an error:
|
||||
///
|
||||
/// ```text
|
||||
/// error: `array` does not live long enough
|
||||
/// for i in &array {
|
||||
/// ^~~~~
|
||||
/// in expansion of for loop expansion
|
||||
/// note: expansion site
|
||||
/// note: reference must be valid for the static lifetime...
|
||||
/// note: ...but borrowed value is only valid for the block suffix following statement 0 at ...
|
||||
/// let array = [1, 2, 3];
|
||||
/// let mut guards = vec![];
|
||||
///
|
||||
/// for i in &array {
|
||||
/// let guard = std::thread::spawn(move || {
|
||||
/// println!("element: {}", i);
|
||||
/// ...
|
||||
/// error: aborting due to previous error
|
||||
/// ```
|
||||
///
|
||||
/// Because [`std::thread::spawn`][spawn] doesn't know about this scope, it requires a
|
||||
/// `'static` lifetime. One way of giving it a proper lifetime is to use an [`Arc`][arc]:
|
||||
///
|
||||
/// [arc]: http://doc.rust-lang.org/stable/std/sync/struct.Arc.html
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let array = Arc::new([1, 2, 3]);
|
||||
/// let mut guards = vec![];
|
||||
///
|
||||
/// for i in (0..array.len()) {
|
||||
/// let a = array.clone();
|
||||
///
|
||||
/// let guard = std::thread::spawn(move || {
|
||||
/// println!("element: {}", a[i]);
|
||||
/// });
|
||||
///
|
||||
/// guards.push(guard);
|
||||
/// }
|
||||
///
|
||||
/// for guard in guards {
|
||||
/// guard.join().unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// But this introduces unnecessary allocation, as `Arc<T>` puts its data on the heap, and we
|
||||
/// also end up dealing with reference counts. We know that we're joining the threads before
|
||||
/// our function returns, so just taking a reference _should_ be safe. Rust can't know that,
|
||||
/// though.
|
||||
///
|
||||
/// Enter scoped threads. Here's our original example, using `spawn` from crossbeam rather
|
||||
/// than from `std::thread`:
|
||||
///
|
||||
/// ```
|
||||
/// let array = [1, 2, 3];
|
||||
///
|
||||
/// crossbeam::scope(|scope| {
|
||||
/// for i in &array {
|
||||
/// scope.spawn(move || {
|
||||
/// println!("element: {}", i);
|
||||
/// });
|
||||
/// }
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// Much more straightforward.
|
||||
pub fn spawn<F, T>(&self, f: F) -> ScopedJoinHandle<T> where
|
||||
F: FnOnce() -> T + Send + 'a, T: Send + 'a
|
||||
{
|
||||
let their_packet = Arc::new(AtomicOption::new());
|
||||
let my_packet = their_packet.clone();
|
||||
|
||||
let join_handle = unsafe {
|
||||
spawn_unsafe(move || {
|
||||
their_packet.swap(f(), Ordering::Relaxed);
|
||||
})
|
||||
};
|
||||
|
||||
let thread = join_handle.thread().clone();
|
||||
let deferred_handle = Rc::new(RefCell::new(JoinState::Running(join_handle)));
|
||||
let my_handle = deferred_handle.clone();
|
||||
|
||||
self.defer(move || {
|
||||
let mut state = deferred_handle.borrow_mut();
|
||||
state.join();
|
||||
});
|
||||
|
||||
ScopedJoinHandle {
|
||||
inner: my_handle,
|
||||
packet: my_packet,
|
||||
thread: thread,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ScopedJoinHandle<T> {
|
||||
/// Join the scoped thread, returning the result it produced.
|
||||
pub fn join(self) -> T {
|
||||
self.inner.borrow_mut().join();
|
||||
self.packet.take(Ordering::Relaxed).unwrap()
|
||||
}
|
||||
|
||||
/// Get the underlying thread handle.
|
||||
pub fn thread(&self) -> &thread::Thread {
|
||||
&self.thread
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for Scope<'a> {
|
||||
fn drop(&mut self) {
|
||||
self.drop_all()
|
||||
}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
/// A type providing atomic storage and retrieval of an `Arc<T>`.
|
||||
#[derive(Debug)]
|
||||
pub struct ArcCell<T>(AtomicUsize, PhantomData<Arc<T>>);
|
||||
|
||||
impl<T> Drop for ArcCell<T> {
|
||||
fn drop(&mut self) {
|
||||
self.take();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ArcCell<T> {
|
||||
/// Creates a new `ArcCell`.
|
||||
pub fn new(t: Arc<T>) -> ArcCell<T> {
|
||||
ArcCell(AtomicUsize::new(unsafe { mem::transmute(t) }), PhantomData)
|
||||
}
|
||||
|
||||
fn take(&self) -> Arc<T> {
|
||||
loop {
|
||||
match self.0.swap(0, Ordering::Acquire) {
|
||||
0 => {}
|
||||
n => return unsafe { mem::transmute(n) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn put(&self, t: Arc<T>) {
|
||||
debug_assert_eq!(self.0.load(Ordering::SeqCst), 0);
|
||||
self.0.store(unsafe { mem::transmute(t) }, Ordering::Release);
|
||||
}
|
||||
|
||||
/// Stores a new value in the `ArcCell`, returning the previous
|
||||
/// value.
|
||||
pub fn set(&self, t: Arc<T>) -> Arc<T> {
|
||||
let old = self.take();
|
||||
self.put(t);
|
||||
old
|
||||
}
|
||||
|
||||
/// Returns a copy of the value stored by the `ArcCell`.
|
||||
pub fn get(&self) -> Arc<T> {
|
||||
let t = self.take();
|
||||
// NB: correctness here depends on Arc's clone impl not panicking
|
||||
let out = t.clone();
|
||||
self.put(t);
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let r = ArcCell::new(Arc::new(0));
|
||||
assert_eq!(*r.get(), 0);
|
||||
assert_eq!(*r.set(Arc::new(1)), 0);
|
||||
assert_eq!(*r.get(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_runs() {
|
||||
static DROPS: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {
|
||||
DROPS.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
let r = ArcCell::new(Arc::new(Foo));
|
||||
let _f = r.get();
|
||||
r.get();
|
||||
r.set(Arc::new(Foo));
|
||||
drop(_f);
|
||||
assert_eq!(DROPS.load(Ordering::SeqCst), 1);
|
||||
drop(r);
|
||||
assert_eq!(DROPS.load(Ordering::SeqCst), 2);
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
use std::sync::atomic::{AtomicPtr, Ordering};
|
||||
use std::ptr;
|
||||
|
||||
unsafe impl<T: Send> Send for AtomicOption<T> {}
|
||||
unsafe impl<T: Send> Sync for AtomicOption<T> {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AtomicOption<T> {
|
||||
inner: AtomicPtr<T>,
|
||||
}
|
||||
|
||||
impl<T> AtomicOption<T> {
|
||||
pub fn new() -> AtomicOption<T> {
|
||||
AtomicOption { inner: AtomicPtr::new(ptr::null_mut()) }
|
||||
}
|
||||
|
||||
fn swap_inner(&self, ptr: *mut T, order: Ordering) -> Option<Box<T>> {
|
||||
let old = self.inner.swap(ptr, order);
|
||||
if old.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { Box::from_raw(old) })
|
||||
}
|
||||
}
|
||||
|
||||
// allows re-use of allocation
|
||||
pub fn swap_box(&self, t: Box<T>, order: Ordering) -> Option<Box<T>> {
|
||||
self.swap_inner(Box::into_raw(t), order)
|
||||
}
|
||||
|
||||
pub fn swap(&self, t: T, order: Ordering) -> Option<T> {
|
||||
self.swap_box(Box::new(t), order).map(|old| *old)
|
||||
}
|
||||
|
||||
pub fn take(&self, order: Ordering) -> Option<T> {
|
||||
self.swap_inner(ptr::null_mut(), order).map(|old| *old)
|
||||
}
|
||||
}
|
|
@ -1,602 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! A lock-free concurrent work-stealing deque
|
||||
//!
|
||||
//! This module contains a hybrid implementation of the Chase-Lev work stealing deque
|
||||
//! described in ["Dynamic Circular Work-Stealing Deque"][chase_lev] and the improved version
|
||||
//! described in ["Correct and Efficient Work-Stealing for Weak Memory Models"][weak_chase_lev].
|
||||
//! The implementation is heavily based on the pseudocode found in the papers.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! use crossbeam::sync::chase_lev;
|
||||
//! let (mut worker, stealer) = chase_lev::deque();
|
||||
//!
|
||||
//! // Only the worker may push/try_pop
|
||||
//! worker.push(1);
|
||||
//! worker.try_pop();
|
||||
//!
|
||||
//! // Stealers take data from the other end of the deque
|
||||
//! worker.push(1);
|
||||
//! stealer.steal();
|
||||
//!
|
||||
//! // Stealers can be cloned to have many stealers stealing in parallel
|
||||
//! worker.push(1);
|
||||
//! let stealer2 = stealer.clone();
|
||||
//! stealer2.steal();
|
||||
//! ```
|
||||
//!
|
||||
//! [chase_lev]: http://neteril.org/~jeremie/Dynamic_Circular_Work_Queue.pdf
|
||||
//! [weak_chase_lev]: http://www.di.ens.fr/~zappa/readings/ppopp13.pdf
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
|
||||
use std::sync::atomic::{AtomicIsize, fence};
|
||||
use std::sync::Arc;
|
||||
|
||||
use mem::epoch::{self, Atomic, Shared, Owned};
|
||||
|
||||
// Once the queue is less than 1/K full, then it will be downsized. Note that
|
||||
// the deque requires that this number be less than 2.
|
||||
const K: isize = 4;
|
||||
|
||||
// Minimum number of bits that a buffer size should be. No buffer will resize to
|
||||
// under this value, and all deques will initially contain a buffer of this
|
||||
// size.
|
||||
//
|
||||
// The size in question is 1 << MIN_BITS
|
||||
const MIN_BITS: u32 = 7;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Deque<T> {
|
||||
bottom: AtomicIsize,
|
||||
top: AtomicIsize,
|
||||
array: Atomic<Buffer<T>>,
|
||||
}
|
||||
|
||||
// FIXME: can these constraints be relaxed?
|
||||
unsafe impl<T: Send> Send for Deque<T> {}
|
||||
unsafe impl<T: Send> Sync for Deque<T> {}
|
||||
|
||||
/// Worker half of the work-stealing deque. This worker has exclusive access to
|
||||
/// one side of the deque, and uses `push` and `try_pop` method to manipulate it.
|
||||
///
|
||||
/// There may only be one worker per deque, and operations on the worker
|
||||
/// require mutable access to the worker itself.
|
||||
#[derive(Debug)]
|
||||
pub struct Worker<T> {
|
||||
deque: Arc<Deque<T>>,
|
||||
}
|
||||
|
||||
/// The stealing half of the work-stealing deque. Stealers have access to the
|
||||
/// opposite end of the deque from the worker, and they only have access to the
|
||||
/// `steal` method.
|
||||
///
|
||||
/// Stealers can be cloned to have more than one handle active at a time.
|
||||
#[derive(Debug)]
|
||||
pub struct Stealer<T> {
|
||||
deque: Arc<Deque<T>>,
|
||||
}
|
||||
|
||||
/// When stealing some data, this is an enumeration of the possible outcomes.
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub enum Steal<T> {
|
||||
/// The deque was empty at the time of stealing
|
||||
Empty,
|
||||
/// The stealer lost the race for stealing data, and a retry may return more
|
||||
/// data.
|
||||
Abort,
|
||||
/// The stealer has successfully stolen some data.
|
||||
Data(T),
|
||||
}
|
||||
|
||||
// An internal buffer used by the chase-lev deque. This structure is actually
|
||||
// implemented as a circular buffer, and is used as the intermediate storage of
|
||||
// the data in the deque.
|
||||
//
|
||||
// This Vec<T> always has a length of 0, the backing buffer is just used by the
|
||||
// code below.
|
||||
struct Buffer<T> {
|
||||
storage: UnsafeCell<Vec<T>>,
|
||||
log_size: u32,
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for Buffer<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Buffer {{ ... }}")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Worker<T> {
|
||||
/// Pushes data onto the front of this work queue.
|
||||
pub fn push(&mut self, t: T) {
|
||||
unsafe { self.deque.push(t) }
|
||||
}
|
||||
|
||||
/// Pops data off the front of the work queue, returning `None` on an empty
|
||||
/// queue.
|
||||
pub fn try_pop(&mut self) -> Option<T> {
|
||||
unsafe { self.deque.try_pop() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Stealer<T> {
|
||||
/// Steals work off the end of the queue (opposite of the worker's end)
|
||||
pub fn steal(&self) -> Steal<T> {
|
||||
self.deque.steal()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Stealer<T> {
|
||||
fn clone(&self) -> Stealer<T> {
|
||||
Stealer { deque: self.deque.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new empty deque
|
||||
pub fn deque<T>() -> (Worker<T>, Stealer<T>) {
|
||||
let a = Arc::new(Deque::new());
|
||||
let b = a.clone();
|
||||
(Worker { deque: a }, Stealer { deque: b })
|
||||
}
|
||||
|
||||
// Almost all of this code can be found directly in the paper so I'm not
|
||||
// personally going to heavily comment what's going on here.
|
||||
|
||||
impl<T> Deque<T> {
|
||||
fn new() -> Deque<T> {
|
||||
let array = Atomic::null();
|
||||
array.store(Some(Owned::new(Buffer::new(MIN_BITS))), SeqCst);
|
||||
Deque {
|
||||
bottom: AtomicIsize::new(0),
|
||||
top: AtomicIsize::new(0),
|
||||
array: array,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn push(&self, data: T) {
|
||||
let guard = epoch::pin();
|
||||
|
||||
let mut b = self.bottom.load(Relaxed);
|
||||
let t = self.top.load(Acquire);
|
||||
let mut a = self.array.load(Relaxed, &guard).unwrap();
|
||||
|
||||
let size = b - t;
|
||||
if size >= (a.size() as isize) - 1 {
|
||||
// You won't find this code in the chase-lev deque paper. This is
|
||||
// alluded to in a small footnote, however. We always free a buffer
|
||||
// when growing in order to prevent leaks.
|
||||
a = self.swap_buffer(a, a.resize(b, t, 1), &guard);
|
||||
|
||||
// reload the bottom counter, since swap_buffer modifies it.
|
||||
b = self.bottom.load(Relaxed);
|
||||
}
|
||||
a.put(b, data);
|
||||
fence(Release);
|
||||
self.bottom.store(b + 1, Relaxed);
|
||||
}
|
||||
|
||||
unsafe fn try_pop(&self) -> Option<T> {
|
||||
let guard = epoch::pin();
|
||||
|
||||
let b = self.bottom.load(Relaxed) - 1;
|
||||
let a = self.array.load(Relaxed, &guard).unwrap();
|
||||
self.bottom.store(b, Relaxed);
|
||||
fence(SeqCst); // the store to bottom must occur before loading top.
|
||||
let t = self.top.load(Relaxed);
|
||||
|
||||
let size = b - t;
|
||||
if size >= 0 {
|
||||
// non-empty case
|
||||
let mut data = Some(a.get(b));
|
||||
if size == 0 {
|
||||
// last element in queue, check for races.
|
||||
if self.top.compare_and_swap(t, t + 1, SeqCst) != t {
|
||||
// lost the race.
|
||||
mem::forget(data.take());
|
||||
}
|
||||
|
||||
// set the queue to a canonically empty state.
|
||||
self.bottom.store(b + 1, Relaxed);
|
||||
} else {
|
||||
self.maybe_shrink(b, t, &guard);
|
||||
}
|
||||
data
|
||||
} else {
|
||||
// empty queue. revert the decrement of "b" and try to shrink.
|
||||
//
|
||||
// the original chase_lev paper uses "t" here, but the new one uses "b + 1".
|
||||
// don't worry, they're the same thing: pop and steal operations will never leave
|
||||
// the top counter greater than the bottom counter. After we decrement "b" at
|
||||
// the beginning of this function, the lowest possible value it could hold here is "t - 1".
|
||||
// That's also the only value that could cause this branch to be taken.
|
||||
self.bottom.store(b + 1, Relaxed);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn steal(&self) -> Steal<T> {
|
||||
let guard = epoch::pin();
|
||||
|
||||
let t = self.top.load(Acquire);
|
||||
fence(SeqCst); // top must be loaded before bottom.
|
||||
let b = self.bottom.load(Acquire);
|
||||
|
||||
let size = b - t;
|
||||
if size <= 0 {
|
||||
return Steal::Empty
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// while the paper uses a "consume" ordering here, the closest thing we have
|
||||
// available is Acquire, which is strictly stronger.
|
||||
let a = self.array.load(Acquire, &guard).unwrap();
|
||||
let data = a.get(t);
|
||||
// we may be racing against other steals and a pop.
|
||||
if self.top.compare_and_swap(t, t + 1, SeqCst) == t {
|
||||
Steal::Data(data)
|
||||
} else {
|
||||
mem::forget(data); // someone else stole this value
|
||||
Steal::Abort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// potentially shrink the array. This can be called only from the worker.
|
||||
unsafe fn maybe_shrink(&self, b: isize, t: isize, guard: &epoch::Guard) {
|
||||
let a = self.array.load(SeqCst, guard).unwrap();
|
||||
let size = b - t;
|
||||
if size < (a.size() as isize) / K && size > (1 << MIN_BITS) {
|
||||
self.swap_buffer(a, a.resize(b, t, -1), guard);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper routine not mentioned in the paper which is used in growing and
|
||||
// shrinking buffers to swap in a new buffer into place.
|
||||
//
|
||||
// As a bit of a recap, stealers can continue using buffers after this
|
||||
// method has called 'unlinked' on it. The continued usage is simply a read
|
||||
// followed by a forget, but we must make sure that the memory can continue
|
||||
// to be read after we flag this buffer for reclamation. All stealers,
|
||||
// however, have their own epoch pinned during this time so the buffer will
|
||||
// just naturally be free'd once all concurrent stealers have exited.
|
||||
//
|
||||
// This method may only be called safely from the workers due to the way it modifies
|
||||
// the array pointer.
|
||||
unsafe fn swap_buffer<'a>(&self,
|
||||
old: Shared<'a, Buffer<T>>,
|
||||
buf: Buffer<T>,
|
||||
guard: &'a epoch::Guard)
|
||||
-> Shared<'a, Buffer<T>> {
|
||||
let newbuf = Owned::new(buf);
|
||||
let newbuf = self.array.store_and_ref(newbuf, Release, &guard);
|
||||
guard.unlinked(old);
|
||||
|
||||
newbuf
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T> Drop for Deque<T> {
|
||||
fn drop(&mut self) {
|
||||
let guard = epoch::pin();
|
||||
|
||||
// Arc enforces that we have truly exclusive access here.
|
||||
|
||||
let t = self.top.load(Relaxed);
|
||||
let b = self.bottom.load(Relaxed);
|
||||
let a = self.array.swap(None, Relaxed, &guard).unwrap();
|
||||
// Free whatever is leftover in the dequeue, then free the backing
|
||||
// memory itself
|
||||
unsafe {
|
||||
for i in t..b {
|
||||
drop(a.get(i));
|
||||
}
|
||||
guard.unlinked(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Buffer<T> {
|
||||
fn new(log_size: u32) -> Buffer<T> {
|
||||
Buffer {
|
||||
storage: UnsafeCell::new(Vec::with_capacity(1 << log_size)),
|
||||
log_size: log_size,
|
||||
}
|
||||
}
|
||||
|
||||
fn size(&self) -> usize {
|
||||
unsafe { (*self.storage.get()).capacity() }
|
||||
}
|
||||
|
||||
fn mask(&self) -> isize {
|
||||
unsafe {
|
||||
((*self.storage.get()).capacity() - 1) as isize
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn elem(&self, i: isize) -> *mut T {
|
||||
(*self.storage.get()).as_mut_ptr().offset(i & self.mask())
|
||||
}
|
||||
|
||||
// This does not protect against loading duplicate values of the same cell,
|
||||
// nor does this clear out the contents contained within. Hence, this is a
|
||||
// very unsafe method which the caller needs to treat specially in case a
|
||||
// race is lost.
|
||||
unsafe fn get(&self, i: isize) -> T {
|
||||
ptr::read(self.elem(i))
|
||||
}
|
||||
|
||||
// Unsafe because this unsafely overwrites possibly uninitialized or
|
||||
// initialized data.
|
||||
unsafe fn put(&self, i: isize, t: T) {
|
||||
ptr::write(self.elem(i), t);
|
||||
}
|
||||
|
||||
// Again, unsafe because this has incredibly dubious ownership violations.
|
||||
// It is assumed that this buffer is immediately dropped.
|
||||
unsafe fn resize(&self, b: isize, t: isize, delta: i32) -> Buffer<T> {
|
||||
let buf = Buffer::new(((self.log_size as i32) + delta) as u32);
|
||||
for i in t..b {
|
||||
buf.put(i, self.get(i));
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate rand;
|
||||
|
||||
use super::{deque, Worker, Stealer, Steal};
|
||||
|
||||
use std::thread;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT,
|
||||
AtomicUsize, ATOMIC_USIZE_INIT};
|
||||
use std::sync::atomic::Ordering::SeqCst;
|
||||
|
||||
use self::rand::Rng;
|
||||
|
||||
#[test]
|
||||
fn smoke() {
|
||||
let (mut w, s) = deque();
|
||||
assert_eq!(w.try_pop(), None);
|
||||
assert_eq!(s.steal(), Steal::Empty);
|
||||
w.push(1);
|
||||
assert_eq!(w.try_pop(), Some(1));
|
||||
w.push(1);
|
||||
assert_eq!(s.steal(), Steal::Data(1));
|
||||
w.push(1);
|
||||
assert_eq!(s.clone().steal(), Steal::Data(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stealpush() {
|
||||
static AMT: isize = 100000;
|
||||
let (mut w, s) = deque();
|
||||
let t = thread::spawn(move || {
|
||||
let mut left = AMT;
|
||||
while left > 0 {
|
||||
match s.steal() {
|
||||
Steal::Data(i) => {
|
||||
assert_eq!(i, 1);
|
||||
left -= 1;
|
||||
}
|
||||
Steal::Abort | Steal::Empty => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for _ in 0..AMT {
|
||||
w.push(1);
|
||||
}
|
||||
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stealpush_large() {
|
||||
static AMT: isize = 100000;
|
||||
let (mut w, s) = deque();
|
||||
let t = thread::spawn(move || {
|
||||
let mut left = AMT;
|
||||
while left > 0 {
|
||||
match s.steal() {
|
||||
Steal::Data((1, 10)) => { left -= 1; }
|
||||
Steal::Data(..) => panic!(),
|
||||
Steal::Abort | Steal::Empty => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for _ in 0..AMT {
|
||||
w.push((1, 10));
|
||||
}
|
||||
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
fn stampede(mut w: Worker<Box<isize>>,
|
||||
s: Stealer<Box<isize>>,
|
||||
nthreads: isize,
|
||||
amt: usize) {
|
||||
for _ in 0..amt {
|
||||
w.push(Box::new(20));
|
||||
}
|
||||
let remaining = Arc::new(AtomicUsize::new(amt));
|
||||
|
||||
let threads = (0..nthreads).map(|_| {
|
||||
let remaining = remaining.clone();
|
||||
let s = s.clone();
|
||||
thread::spawn(move || {
|
||||
while remaining.load(SeqCst) > 0 {
|
||||
match s.steal() {
|
||||
Steal::Data(val) => {
|
||||
if *val == 20 {
|
||||
remaining.fetch_sub(1, SeqCst);
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
Steal::Abort | Steal::Empty => {}
|
||||
}
|
||||
}
|
||||
})
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
while remaining.load(SeqCst) > 0 {
|
||||
if let Some(val) = w.try_pop() {
|
||||
if *val == 20 {
|
||||
remaining.fetch_sub(1, SeqCst);
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for thread in threads.into_iter() {
|
||||
thread.join().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_stampede() {
|
||||
let (w, s) = deque();
|
||||
stampede(w, s, 8, 10000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many_stampede() {
|
||||
static AMT: usize = 4;
|
||||
let threads = (0..AMT).map(|_| {
|
||||
let (w, s) = deque();
|
||||
thread::spawn(|| {
|
||||
stampede(w, s, 4, 10000);
|
||||
})
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
for thread in threads.into_iter() {
|
||||
thread.join().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stress() {
|
||||
static AMT: isize = 100000;
|
||||
static NTHREADS: isize = 8;
|
||||
static DONE: AtomicBool = ATOMIC_BOOL_INIT;
|
||||
static HITS: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
let (mut w, s) = deque();
|
||||
|
||||
let threads = (0..NTHREADS).map(|_| {
|
||||
let s = s.clone();
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
match s.steal() {
|
||||
Steal::Data(2) => { HITS.fetch_add(1, SeqCst); }
|
||||
Steal::Data(..) => panic!(),
|
||||
_ if DONE.load(SeqCst) => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
})
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut expected = 0;
|
||||
while expected < AMT {
|
||||
if rng.gen_range(0, 3) == 2 {
|
||||
match w.try_pop() {
|
||||
None => {}
|
||||
Some(2) => { HITS.fetch_add(1, SeqCst); },
|
||||
Some(_) => panic!(),
|
||||
}
|
||||
} else {
|
||||
expected += 1;
|
||||
w.push(2);
|
||||
}
|
||||
}
|
||||
|
||||
while HITS.load(SeqCst) < AMT as usize {
|
||||
match w.try_pop() {
|
||||
None => {}
|
||||
Some(2) => { HITS.fetch_add(1, SeqCst); },
|
||||
Some(_) => panic!(),
|
||||
}
|
||||
}
|
||||
DONE.store(true, SeqCst);
|
||||
|
||||
for thread in threads.into_iter() {
|
||||
thread.join().unwrap();
|
||||
}
|
||||
|
||||
assert_eq!(HITS.load(SeqCst), expected as usize);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_starvation() {
|
||||
static AMT: isize = 10000;
|
||||
static NTHREADS: isize = 4;
|
||||
static DONE: AtomicBool = ATOMIC_BOOL_INIT;
|
||||
let (mut w, s) = deque();
|
||||
|
||||
let (threads, hits): (Vec<_>, Vec<_>) = (0..NTHREADS).map(|_| {
|
||||
let s = s.clone();
|
||||
let ctr = Arc::new(AtomicUsize::new(0));
|
||||
let ctr2 = ctr.clone();
|
||||
(thread::spawn(move || {
|
||||
loop {
|
||||
match s.steal() {
|
||||
Steal::Data((1, 2)) => { ctr.fetch_add(1, SeqCst); }
|
||||
Steal::Data(..) => panic!(),
|
||||
_ if DONE.load(SeqCst) => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}), ctr2)
|
||||
}).unzip();
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut myhit = false;
|
||||
'outer: loop {
|
||||
for _ in 0..rng.gen_range(0, AMT) {
|
||||
if !myhit && rng.gen_range(0, 3) == 2 {
|
||||
match w.try_pop() {
|
||||
None => {}
|
||||
Some((1, 2)) => myhit = true,
|
||||
Some(_) => panic!(),
|
||||
}
|
||||
} else {
|
||||
w.push((1, 2));
|
||||
}
|
||||
}
|
||||
|
||||
for slot in hits.iter() {
|
||||
let amt = slot.load(SeqCst);
|
||||
if amt == 0 { continue 'outer; }
|
||||
}
|
||||
if myhit {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
DONE.store(true, SeqCst);
|
||||
|
||||
for thread in threads.into_iter() {
|
||||
thread.join().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
//! Synchronization primitives.
|
||||
|
||||
pub use self::ms_queue::MsQueue;
|
||||
pub use self::atomic_option::AtomicOption;
|
||||
pub use self::treiber_stack::TreiberStack;
|
||||
pub use self::seg_queue::SegQueue;
|
||||
pub use self::arc_cell::ArcCell;
|
||||
|
||||
mod atomic_option;
|
||||
mod ms_queue;
|
||||
mod treiber_stack;
|
||||
mod seg_queue;
|
||||
pub mod chase_lev;
|
||||
mod arc_cell;
|
|
@ -1,511 +0,0 @@
|
|||
use std::sync::atomic::Ordering::{Acquire, Release, Relaxed};
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::{ptr, mem};
|
||||
use std::thread::{self, Thread};
|
||||
|
||||
use mem::epoch::{self, Atomic, Owned, Shared};
|
||||
use mem::CachePadded;
|
||||
|
||||
/// A Michael-Scott lock-free queue, with support for blocking `pop`s.
|
||||
///
|
||||
/// Usable with any number of producers and consumers.
|
||||
// The representation here is a singly-linked list, with a sentinel
|
||||
// node at the front. In general the `tail` pointer may lag behind the
|
||||
// actual tail. Non-sentinal nodes are either all `Data` or all
|
||||
// `Blocked` (requests for data from blocked threads).
|
||||
#[derive(Debug)]
|
||||
pub struct MsQueue<T> {
|
||||
head: CachePadded<Atomic<Node<T>>>,
|
||||
tail: CachePadded<Atomic<Node<T>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Node<T> {
|
||||
payload: Payload<T>,
|
||||
next: Atomic<Node<T>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Payload<T> {
|
||||
/// A node with actual data that can be popped.
|
||||
Data(T),
|
||||
/// A node representing a blocked request for data.
|
||||
Blocked(*mut Signal<T>),
|
||||
}
|
||||
|
||||
/// A blocked request for data, which includes a slot to write the data.
|
||||
#[derive(Debug)]
|
||||
struct Signal<T> {
|
||||
/// Thread to unpark when data is ready.
|
||||
thread: Thread,
|
||||
/// The actual data, when available.
|
||||
data: Option<T>,
|
||||
/// Is the data ready? Needed to cope with spurious wakeups.
|
||||
ready: AtomicBool,
|
||||
}
|
||||
|
||||
impl<T> Node<T> {
|
||||
fn is_data(&self) -> bool {
|
||||
if let Payload::Data(_) = self.payload { true } else { false }
|
||||
}
|
||||
}
|
||||
|
||||
// Any particular `T` should never accessed concurrently, so no need
|
||||
// for Sync.
|
||||
unsafe impl<T: Send> Sync for MsQueue<T> {}
|
||||
unsafe impl<T: Send> Send for MsQueue<T> {}
|
||||
|
||||
impl<T> MsQueue<T> {
|
||||
/// Create a new, empty queue.
|
||||
pub fn new() -> MsQueue<T> {
|
||||
let q = MsQueue {
|
||||
head: CachePadded::new(Atomic::null()),
|
||||
tail: CachePadded::new(Atomic::null()),
|
||||
};
|
||||
let sentinel = Owned::new(Node {
|
||||
payload: Payload::Data(unsafe { mem::uninitialized() }),
|
||||
next: Atomic::null(),
|
||||
});
|
||||
let guard = epoch::pin();
|
||||
let sentinel = q.head.store_and_ref(sentinel, Relaxed, &guard);
|
||||
q.tail.store_shared(Some(sentinel), Relaxed);
|
||||
q
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
/// Attempt to atomically place `n` into the `next` pointer of `onto`.
|
||||
///
|
||||
/// If unsuccessful, returns ownership of `n`, possibly updating
|
||||
/// the queue's `tail` pointer.
|
||||
fn push_internal(&self,
|
||||
guard: &epoch::Guard,
|
||||
onto: Shared<Node<T>>,
|
||||
n: Owned<Node<T>>)
|
||||
-> Result<(), Owned<Node<T>>>
|
||||
{
|
||||
// is `onto` the actual tail?
|
||||
if let Some(next) = onto.next.load(Acquire, guard) {
|
||||
// if not, try to "help" by moving the tail pointer forward
|
||||
self.tail.cas_shared(Some(onto), Some(next), Release);
|
||||
Err(n)
|
||||
} else {
|
||||
// looks like the actual tail; attempt to link in `n`
|
||||
onto.next.cas_and_ref(None, n, Release, guard).map(|shared| {
|
||||
// try to move the tail pointer forward
|
||||
self.tail.cas_shared(Some(onto), Some(shared), Release);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Add `t` to the back of the queue, possibly waking up threads
|
||||
/// blocked on `pop`.
|
||||
pub fn push(&self, t: T) {
|
||||
/// We may or may not need to allocate a node; once we do,
|
||||
/// we cache that allocation.
|
||||
enum Cache<T> {
|
||||
Data(T),
|
||||
Node(Owned<Node<T>>),
|
||||
}
|
||||
|
||||
impl<T> Cache<T> {
|
||||
/// Extract the node if cached, or allocate if not.
|
||||
fn into_node(self) -> Owned<Node<T>> {
|
||||
match self {
|
||||
Cache::Data(t) => {
|
||||
Owned::new(Node {
|
||||
payload: Payload::Data(t),
|
||||
next: Atomic::null()
|
||||
})
|
||||
}
|
||||
Cache::Node(n) => n
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract the data from the cache, deallocating any cached node.
|
||||
fn into_data(self) -> T {
|
||||
match self {
|
||||
Cache::Data(t) => t,
|
||||
Cache::Node(node) => {
|
||||
match node.into_inner().payload {
|
||||
Payload::Data(t) => t,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut cache = Cache::Data(t); // don't allocate up front
|
||||
let guard = epoch::pin();
|
||||
|
||||
loop {
|
||||
// We push onto the tail, so we'll start optimistically by looking
|
||||
// there first.
|
||||
let tail = self.tail.load(Acquire, &guard).unwrap();
|
||||
|
||||
// Is the queue in Data mode (empty queues can be viewed as either mode)?
|
||||
if tail.is_data() ||
|
||||
self.head.load(Relaxed, &guard).unwrap().as_raw() == tail.as_raw()
|
||||
{
|
||||
// Attempt to push onto the `tail` snapshot; fails if
|
||||
// `tail.next` has changed, which will always be the case if the
|
||||
// queue has transitioned to blocking mode.
|
||||
match self.push_internal(&guard, tail, cache.into_node()) {
|
||||
Ok(_) => return,
|
||||
Err(n) => {
|
||||
// replace the cache, retry whole thing
|
||||
cache = Cache::Node(n)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Queue is in blocking mode. Attempt to unblock a thread.
|
||||
let head = self.head.load(Acquire, &guard).unwrap();
|
||||
// Get a handle on the first blocked node. Racy, so queue might
|
||||
// be empty or in data mode by the time we see it.
|
||||
let request = head.next.load(Acquire, &guard).and_then(|next| {
|
||||
match next.payload {
|
||||
Payload::Blocked(signal) => Some((next, signal)),
|
||||
Payload::Data(_) => None,
|
||||
}
|
||||
});
|
||||
if let Some((blocked_node, signal)) = request {
|
||||
// race to dequeue the node
|
||||
if self.head.cas_shared(Some(head), Some(blocked_node), Release) {
|
||||
unsafe {
|
||||
// signal the thread
|
||||
(*signal).data = Some(cache.into_data());
|
||||
(*signal).ready.store(true, Relaxed);
|
||||
(*signal).thread.unpark();
|
||||
guard.unlinked(head);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
// Attempt to pop a data node. `Ok(None)` if queue is empty or in blocking
|
||||
// mode; `Err(())` if lost race to pop.
|
||||
fn pop_internal(&self, guard: &epoch::Guard) -> Result<Option<T>, ()> {
|
||||
let head = self.head.load(Acquire, guard).unwrap();
|
||||
if let Some(next) = head.next.load(Acquire, guard) {
|
||||
if let Payload::Data(ref t) = next.payload {
|
||||
unsafe {
|
||||
if self.head.cas_shared(Some(head), Some(next), Release) {
|
||||
guard.unlinked(head);
|
||||
Ok(Some(ptr::read(t)))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if this queue is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
let guard = epoch::pin();
|
||||
let head = self.head.load(Acquire, &guard).unwrap();
|
||||
|
||||
if let Some(next) = head.next.load(Acquire, &guard) {
|
||||
if let Payload::Data(_) = next.payload {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to dequeue from the front.
|
||||
///
|
||||
/// Returns `None` if the queue is observed to be empty.
|
||||
pub fn try_pop(&self) -> Option<T> {
|
||||
let guard = epoch::pin();
|
||||
loop {
|
||||
if let Ok(r) = self.pop_internal(&guard) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Dequeue an element from the front of the queue, blocking if the queue is
|
||||
/// empty.
|
||||
pub fn pop(&self) -> T {
|
||||
let guard = epoch::pin();
|
||||
|
||||
// Fast path: keep retrying until we observe that the queue has no data,
|
||||
// avoiding the allocation of a blocked node.
|
||||
loop {
|
||||
match self.pop_internal(&guard) {
|
||||
Ok(Some(r)) => {
|
||||
return r;
|
||||
}
|
||||
Ok(None) => {
|
||||
break;
|
||||
}
|
||||
Err(()) => {}
|
||||
}
|
||||
}
|
||||
|
||||
// The signal gets to live on the stack, since this stack frame will be
|
||||
// blocked until receiving the signal.
|
||||
let mut signal = Signal {
|
||||
thread: thread::current(),
|
||||
data: None,
|
||||
ready: AtomicBool::new(false),
|
||||
};
|
||||
|
||||
// Go ahead and allocate the blocked node; chances are, we'll need it.
|
||||
let mut node = Owned::new(Node {
|
||||
payload: Payload::Blocked(&mut signal),
|
||||
next: Atomic::null(),
|
||||
});
|
||||
|
||||
loop {
|
||||
// try a normal pop
|
||||
if let Ok(Some(r)) = self.pop_internal(&guard) {
|
||||
return r;
|
||||
}
|
||||
|
||||
// At this point, we believe the queue is empty/blocked.
|
||||
// Snapshot the tail, onto which we want to push a blocked node.
|
||||
let tail = self.tail.load(Relaxed, &guard).unwrap();
|
||||
|
||||
// Double-check that we're in blocking mode
|
||||
if tail.is_data() {
|
||||
// The current tail is in data mode, so we probably need to abort.
|
||||
// BUT, it might be the sentinel, so check for that first.
|
||||
let head = self.head.load(Relaxed, &guard).unwrap();
|
||||
if tail.is_data() && tail.as_raw() != head.as_raw() { continue; }
|
||||
}
|
||||
|
||||
// At this point, the tail snapshot is either a blocked node deep in
|
||||
// the queue, the sentinel, or no longer accessible from the queue.
|
||||
// In *ALL* of these cases, if we succeed in pushing onto the
|
||||
// snapshot, we know we are maintaining the core invariant: all
|
||||
// reachable, non-sentinel nodes have the same payload mode, in this
|
||||
// case, blocked.
|
||||
match self.push_internal(&guard, tail, node) {
|
||||
Ok(()) => {
|
||||
while !signal.ready.load(Relaxed) {
|
||||
thread::park();
|
||||
}
|
||||
return signal.data.unwrap();
|
||||
}
|
||||
Err(n) => {
|
||||
node = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
const CONC_COUNT: i64 = 1000000;
|
||||
|
||||
use scope;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn push_try_pop_1() {
|
||||
let q: MsQueue<i64> = MsQueue::new();
|
||||
assert!(q.is_empty());
|
||||
q.push(37);
|
||||
assert!(!q.is_empty());
|
||||
assert_eq!(q.try_pop(), Some(37));
|
||||
assert!(q.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_try_pop_2() {
|
||||
let q: MsQueue<i64> = MsQueue::new();
|
||||
assert!(q.is_empty());
|
||||
q.push(37);
|
||||
q.push(48);
|
||||
assert_eq!(q.try_pop(), Some(37));
|
||||
assert!(!q.is_empty());
|
||||
assert_eq!(q.try_pop(), Some(48));
|
||||
assert!(q.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_try_pop_many_seq() {
|
||||
let q: MsQueue<i64> = MsQueue::new();
|
||||
assert!(q.is_empty());
|
||||
for i in 0..200 {
|
||||
q.push(i)
|
||||
}
|
||||
assert!(!q.is_empty());
|
||||
for i in 0..200 {
|
||||
assert_eq!(q.try_pop(), Some(i));
|
||||
}
|
||||
assert!(q.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_pop_1() {
|
||||
let q: MsQueue<i64> = MsQueue::new();
|
||||
assert!(q.is_empty());
|
||||
q.push(37);
|
||||
assert!(!q.is_empty());
|
||||
assert_eq!(q.pop(), 37);
|
||||
assert!(q.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_pop_2() {
|
||||
let q: MsQueue<i64> = MsQueue::new();
|
||||
q.push(37);
|
||||
q.push(48);
|
||||
assert_eq!(q.pop(), 37);
|
||||
assert_eq!(q.pop(), 48);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_pop_many_seq() {
|
||||
let q: MsQueue<i64> = MsQueue::new();
|
||||
assert!(q.is_empty());
|
||||
for i in 0..200 {
|
||||
q.push(i)
|
||||
}
|
||||
assert!(!q.is_empty());
|
||||
for i in 0..200 {
|
||||
assert_eq!(q.pop(), i);
|
||||
}
|
||||
assert!(q.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_try_pop_many_spsc() {
|
||||
let q: MsQueue<i64> = MsQueue::new();
|
||||
assert!(q.is_empty());
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(|| {
|
||||
let mut next = 0;
|
||||
|
||||
while next < CONC_COUNT {
|
||||
if let Some(elem) = q.try_pop() {
|
||||
assert_eq!(elem, next);
|
||||
next += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for i in 0..CONC_COUNT {
|
||||
q.push(i)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_try_pop_many_spmc() {
|
||||
fn recv(_t: i32, q: &MsQueue<i64>) {
|
||||
let mut cur = -1;
|
||||
for _i in 0..CONC_COUNT {
|
||||
if let Some(elem) = q.try_pop() {
|
||||
assert!(elem > cur);
|
||||
cur = elem;
|
||||
|
||||
if cur == CONC_COUNT - 1 { break }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let q: MsQueue<i64> = MsQueue::new();
|
||||
assert!(q.is_empty());
|
||||
let qr = &q;
|
||||
scope(|scope| {
|
||||
for i in 0..3 {
|
||||
scope.spawn(move || recv(i, qr));
|
||||
}
|
||||
|
||||
scope.spawn(|| {
|
||||
for i in 0..CONC_COUNT {
|
||||
q.push(i);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_try_pop_many_mpmc() {
|
||||
enum LR { Left(i64), Right(i64) }
|
||||
|
||||
let q: MsQueue<LR> = MsQueue::new();
|
||||
assert!(q.is_empty());
|
||||
|
||||
scope(|scope| {
|
||||
for _t in 0..2 {
|
||||
scope.spawn(|| {
|
||||
for i in CONC_COUNT-1..CONC_COUNT {
|
||||
q.push(LR::Left(i))
|
||||
}
|
||||
});
|
||||
scope.spawn(|| {
|
||||
for i in CONC_COUNT-1..CONC_COUNT {
|
||||
q.push(LR::Right(i))
|
||||
}
|
||||
});
|
||||
scope.spawn(|| {
|
||||
let mut vl = vec![];
|
||||
let mut vr = vec![];
|
||||
for _i in 0..CONC_COUNT {
|
||||
match q.try_pop() {
|
||||
Some(LR::Left(x)) => vl.push(x),
|
||||
Some(LR::Right(x)) => vr.push(x),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let mut vl2 = vl.clone();
|
||||
let mut vr2 = vr.clone();
|
||||
vl2.sort();
|
||||
vr2.sort();
|
||||
|
||||
assert_eq!(vl, vl2);
|
||||
assert_eq!(vr, vr2);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_pop_many_spsc() {
|
||||
let q: MsQueue<i64> = MsQueue::new();
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(|| {
|
||||
let mut next = 0;
|
||||
while next < CONC_COUNT {
|
||||
assert_eq!(q.pop(), next);
|
||||
next += 1;
|
||||
}
|
||||
});
|
||||
|
||||
for i in 0..CONC_COUNT {
|
||||
q.push(i)
|
||||
}
|
||||
});
|
||||
assert!(q.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_empty_dont_pop() {
|
||||
let q: MsQueue<i64> = MsQueue::new();
|
||||
q.push(20);
|
||||
q.push(20);
|
||||
assert!(!q.is_empty());
|
||||
assert!(!q.is_empty());
|
||||
assert!(q.try_pop().is_some());
|
||||
}
|
||||
}
|
|
@ -1,251 +0,0 @@
|
|||
use std::sync::atomic::Ordering::{Acquire, Release, Relaxed};
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize};
|
||||
use std::fmt;
|
||||
use std::{ptr, mem};
|
||||
use std::cmp;
|
||||
use std::cell::UnsafeCell;
|
||||
|
||||
use mem::epoch::{self, Atomic, Owned};
|
||||
|
||||
const SEG_SIZE: usize = 32;
|
||||
|
||||
/// A Michael-Scott queue that allocates "segments" (arrays of nodes)
|
||||
/// for efficiency.
|
||||
///
|
||||
/// Usable with any number of producers and consumers.
|
||||
#[derive(Debug)]
|
||||
pub struct SegQueue<T> {
|
||||
head: Atomic<Segment<T>>,
|
||||
tail: Atomic<Segment<T>>,
|
||||
}
|
||||
|
||||
struct Segment<T> {
|
||||
low: AtomicUsize,
|
||||
data: [UnsafeCell<(T, AtomicBool)>; SEG_SIZE],
|
||||
high: AtomicUsize,
|
||||
next: Atomic<Segment<T>>,
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for Segment<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Segment {{ ... }}")
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Sync for Segment<T> {}
|
||||
|
||||
impl<T> Segment<T> {
|
||||
fn new() -> Segment<T> {
|
||||
let rqueue = Segment {
|
||||
data: unsafe { mem::uninitialized() },
|
||||
low: AtomicUsize::new(0),
|
||||
high: AtomicUsize::new(0),
|
||||
next: Atomic::null(),
|
||||
};
|
||||
for val in rqueue.data.iter() {
|
||||
unsafe {
|
||||
(*val.get()).1 = AtomicBool::new(false);
|
||||
}
|
||||
}
|
||||
rqueue
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SegQueue<T> {
|
||||
/// Create a new, empty queue.
|
||||
pub fn new() -> SegQueue<T> {
|
||||
let q = SegQueue {
|
||||
head: Atomic::null(),
|
||||
tail: Atomic::null(),
|
||||
};
|
||||
let sentinel = Owned::new(Segment::new());
|
||||
let guard = epoch::pin();
|
||||
let sentinel = q.head.store_and_ref(sentinel, Relaxed, &guard);
|
||||
q.tail.store_shared(Some(sentinel), Relaxed);
|
||||
q
|
||||
}
|
||||
|
||||
/// Add `t` to the back of the queue.
|
||||
pub fn push(&self, t: T) {
|
||||
let guard = epoch::pin();
|
||||
loop {
|
||||
let tail = self.tail.load(Acquire, &guard).unwrap();
|
||||
if tail.high.load(Relaxed) >= SEG_SIZE { continue }
|
||||
let i = tail.high.fetch_add(1, Relaxed);
|
||||
unsafe {
|
||||
if i < SEG_SIZE {
|
||||
let cell = (*tail).data.get_unchecked(i).get();
|
||||
ptr::write(&mut (*cell).0, t);
|
||||
(*cell).1.store(true, Release);
|
||||
|
||||
if i + 1 == SEG_SIZE {
|
||||
let tail = tail.next.store_and_ref(Owned::new(Segment::new()), Release, &guard);
|
||||
self.tail.store_shared(Some(tail), Release);
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to dequeue from the front.
|
||||
///
|
||||
/// Returns `None` if the queue is observed to be empty.
|
||||
pub fn try_pop(&self) -> Option<T> {
|
||||
let guard = epoch::pin();
|
||||
loop {
|
||||
let head = self.head.load(Acquire, &guard).unwrap();
|
||||
loop {
|
||||
let low = head.low.load(Relaxed);
|
||||
if low >= cmp::min(head.high.load(Relaxed), SEG_SIZE) { break }
|
||||
if head.low.compare_and_swap(low, low+1, Relaxed) == low {
|
||||
unsafe {
|
||||
let cell = (*head).data.get_unchecked(low).get();
|
||||
loop {
|
||||
if (*cell).1.load(Acquire) { break }
|
||||
}
|
||||
if low + 1 == SEG_SIZE {
|
||||
loop {
|
||||
if let Some(next) = head.next.load(Acquire, &guard) {
|
||||
self.head.store_shared(Some(next), Release);
|
||||
guard.unlinked(head);
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return Some(ptr::read(&(*cell).0))
|
||||
}
|
||||
}
|
||||
}
|
||||
if head.next.load(Relaxed, &guard).is_none() { return None }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
const CONC_COUNT: i64 = 1000000;
|
||||
|
||||
use scope;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn push_pop_1() {
|
||||
let q: SegQueue<i64> = SegQueue::new();
|
||||
q.push(37);
|
||||
assert_eq!(q.try_pop(), Some(37));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_pop_2() {
|
||||
let q: SegQueue<i64> = SegQueue::new();
|
||||
q.push(37);
|
||||
q.push(48);
|
||||
assert_eq!(q.try_pop(), Some(37));
|
||||
assert_eq!(q.try_pop(), Some(48));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_pop_many_seq() {
|
||||
let q: SegQueue<i64> = SegQueue::new();
|
||||
for i in 0..200 {
|
||||
q.push(i)
|
||||
}
|
||||
for i in 0..200 {
|
||||
assert_eq!(q.try_pop(), Some(i));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_pop_many_spsc() {
|
||||
let q: SegQueue<i64> = SegQueue::new();
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(|| {
|
||||
let mut next = 0;
|
||||
|
||||
while next < CONC_COUNT {
|
||||
if let Some(elem) = q.try_pop() {
|
||||
assert_eq!(elem, next);
|
||||
next += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for i in 0..CONC_COUNT {
|
||||
q.push(i)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_pop_many_spmc() {
|
||||
fn recv(_t: i32, q: &SegQueue<i64>) {
|
||||
let mut cur = -1;
|
||||
for _i in 0..CONC_COUNT {
|
||||
if let Some(elem) = q.try_pop() {
|
||||
assert!(elem > cur);
|
||||
cur = elem;
|
||||
|
||||
if cur == CONC_COUNT - 1 { break }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let q: SegQueue<i64> = SegQueue::new();
|
||||
let qr = &q;
|
||||
scope(|scope| {
|
||||
for i in 0..3 {
|
||||
scope.spawn(move || recv(i, qr));
|
||||
}
|
||||
|
||||
scope.spawn(|| {
|
||||
for i in 0..CONC_COUNT {
|
||||
q.push(i);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_pop_many_mpmc() {
|
||||
enum LR { Left(i64), Right(i64) }
|
||||
|
||||
let q: SegQueue<LR> = SegQueue::new();
|
||||
|
||||
scope(|scope| {
|
||||
for _t in 0..2 {
|
||||
scope.spawn(|| {
|
||||
for i in CONC_COUNT-1..CONC_COUNT {
|
||||
q.push(LR::Left(i))
|
||||
}
|
||||
});
|
||||
scope.spawn(|| {
|
||||
for i in CONC_COUNT-1..CONC_COUNT {
|
||||
q.push(LR::Right(i))
|
||||
}
|
||||
});
|
||||
scope.spawn(|| {
|
||||
let mut vl = vec![];
|
||||
let mut vr = vec![];
|
||||
for _i in 0..CONC_COUNT {
|
||||
match q.try_pop() {
|
||||
Some(LR::Left(x)) => vl.push(x),
|
||||
Some(LR::Right(x)) => vr.push(x),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let mut vl2 = vl.clone();
|
||||
let mut vr2 = vr.clone();
|
||||
vl2.sort();
|
||||
vr2.sort();
|
||||
|
||||
assert_eq!(vl, vl2);
|
||||
assert_eq!(vr, vr2);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
use std::sync::atomic::Ordering::{Acquire, Release, Relaxed};
|
||||
use std::ptr;
|
||||
|
||||
use mem::epoch::{self, Atomic, Owned};
|
||||
|
||||
/// Treiber's lock-free stack.
|
||||
///
|
||||
/// Usable with any number of producers and consumers.
|
||||
#[derive(Debug)]
|
||||
pub struct TreiberStack<T> {
|
||||
head: Atomic<Node<T>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Node<T> {
|
||||
data: T,
|
||||
next: Atomic<Node<T>>,
|
||||
}
|
||||
|
||||
impl<T> TreiberStack<T> {
|
||||
/// Create a new, empty stack.
|
||||
pub fn new() -> TreiberStack<T> {
|
||||
TreiberStack { head: Atomic::null() }
|
||||
}
|
||||
|
||||
/// Push `t` on top of the stack.
|
||||
pub fn push(&self, t: T) {
|
||||
let mut n = Owned::new(Node {
|
||||
data: t,
|
||||
next: Atomic::null(),
|
||||
});
|
||||
let guard = epoch::pin();
|
||||
loop {
|
||||
let head = self.head.load(Relaxed, &guard);
|
||||
n.next.store_shared(head, Relaxed);
|
||||
match self.head.cas_and_ref(head, n, Release, &guard) {
|
||||
Ok(_) => break,
|
||||
Err(owned) => n = owned,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to pop the top element of the stack.
|
||||
/// **Deprecated method**, use try_pop
|
||||
///
|
||||
/// Returns `None` if the stack is observed to be empty.
|
||||
#[cfg_attr(any(feature="beta", feature="nightly"), deprecated(note="The pop method has been renamed to try_pop for consistency with other collections."))]
|
||||
pub fn pop(&self) -> Option<T> {
|
||||
self.try_pop()
|
||||
}
|
||||
|
||||
/// Attempt to pop the top element of the stack.
|
||||
///
|
||||
/// Returns `None` if the stack is observed to be empty.
|
||||
pub fn try_pop(&self) -> Option<T> {
|
||||
let guard = epoch::pin();
|
||||
loop {
|
||||
match self.head.load(Acquire, &guard) {
|
||||
Some(head) => {
|
||||
let next = head.next.load(Relaxed, &guard);
|
||||
if self.head.cas_shared(Some(head), next, Release) {
|
||||
unsafe {
|
||||
guard.unlinked(head);
|
||||
return Some(ptr::read(&(*head).data));
|
||||
}
|
||||
}
|
||||
}
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if this queue is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
let guard = epoch::pin();
|
||||
self.head.load(Acquire, &guard).is_none()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn is_empty() {
|
||||
let q: TreiberStack<i64> = TreiberStack::new();
|
||||
assert!(q.is_empty());
|
||||
q.push(20);
|
||||
q.push(20);
|
||||
assert!(!q.is_empty());
|
||||
assert!(!q.is_empty());
|
||||
assert!(q.try_pop().is_some());
|
||||
assert!(q.try_pop().is_some());
|
||||
assert!(q.is_empty());
|
||||
q.push(25);
|
||||
assert!(!q.is_empty());
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
{"files":{".travis.yml":"023fbba79a890f1285fba26903ffb000e32c596cb1794d5e4ae64c003cf44f50","Cargo.toml":"3024d1fa541d30eba222b7b775b9bf7b4498b3b6168cf8052aa1d2de13403c50","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"f40b08aaee5559ba4769e5449188fc2a6364d1e0eac57499cdac3fc2be30aeef","README.md":"fcb9d4f832f28616afa8a9a79549331f78787dedfa167156ae59dee751a885cd","appveyor.yml":"17cb92b1e92399402ab1dd7639ba28cea71079d2bdd8fab5cd4d40ab4351940b","src/lib.rs":"71b6383cb72398d413c9fccc72c15e5962ec59b6c0dd53d1dfa059655e51f686"},"package":"00c9301a947a2eaee7ce2556b80285dcc89558d07088962e6e8b9c25730f9dc6"}
|
|
@ -1,12 +0,0 @@
|
|||
sudo: false
|
||||
|
||||
language: rust
|
||||
|
||||
rust:
|
||||
- 1.8.0
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
|
||||
script:
|
||||
- cargo build --verbose
|
|
@ -1,35 +0,0 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "isatty"
|
||||
version = "0.1.5"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
description = "libc::isatty that also works on Windows"
|
||||
documentation = "https://github.com/dtolnay/isatty"
|
||||
readme = "README.md"
|
||||
keywords = ["tty"]
|
||||
categories = ["command-line-interface"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/dtolnay/isatty"
|
||||
[target."cfg(windows)".dependencies.winapi]
|
||||
version = "0.2"
|
||||
|
||||
[target."cfg(windows)".dependencies.kernel32-sys]
|
||||
version = "0.2"
|
||||
[target."cfg(unix)".dependencies.libc]
|
||||
version = "0.2"
|
||||
[badges.travis-ci]
|
||||
repository = "dtolnay/isatty"
|
||||
|
||||
[badges.appveyor]
|
||||
repository = "dtolnay/isatty"
|
|
@ -1,201 +0,0 @@
|
|||
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 [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
|
@ -1,25 +0,0 @@
|
|||
Copyright (c) 2016
|
||||
|
||||
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.
|
|
@ -1,61 +0,0 @@
|
|||
# Rust isatty
|
||||
|
||||
[![Build Status](https://travis-ci.org/dtolnay/isatty.svg?branch=master)](https://travis-ci.org/dtolnay/isatty)
|
||||
[![Build Status](https://ci.appveyor.com/api/projects/status/5aq0inkv7eip6udp/branch/master?svg=true)](https://ci.appveyor.com/project/dtolnay/isatty/branch/master)
|
||||
[![Latest Version](https://img.shields.io/crates/v/isatty.svg)](https://crates.io/crates/isatty)
|
||||
|
||||
This crate provides the following three functions:
|
||||
|
||||
```rust
|
||||
fn stdin_isatty() -> bool
|
||||
fn stdout_isatty() -> bool
|
||||
fn stderr_isatty() -> bool
|
||||
```
|
||||
|
||||
On Linux and Mac they are implemented with [`libc::isatty`]. On Windows they are
|
||||
implemented with [`kernel32::GetConsoleMode`].
|
||||
|
||||
[`libc::isatty`]: http://man7.org/linux/man-pages/man3/isatty.3.html
|
||||
[`kernel32::GetConsoleMode`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms683167.aspx
|
||||
|
||||
The `stdin_isatty` function is not yet implemented for Windows. If you need it,
|
||||
please check [dtolnay/isatty#1] and contribute an implementation!
|
||||
|
||||
[dtolnay/isatty#1]: https://github.com/dtolnay/isatty/issues/1
|
||||
|
||||
## Usage
|
||||
|
||||
`Cargo.toml`
|
||||
|
||||
> ```toml
|
||||
> [dependencies]
|
||||
> isatty = "0.1"
|
||||
> ```
|
||||
|
||||
`src/main.rs`
|
||||
|
||||
> ```rust
|
||||
> extern crate isatty;
|
||||
> use isatty::{stdin_isatty, stdout_isatty, stderr_isatty};
|
||||
>
|
||||
> fn main() {
|
||||
> println!("stdin: {}", stdin_isatty());
|
||||
> println!("stdout: {}", stdout_isatty());
|
||||
> println!("stderr: {}", stderr_isatty());
|
||||
> }
|
||||
> ```
|
||||
|
||||
## 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 isatty by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
|
@ -1,18 +0,0 @@
|
|||
environment:
|
||||
matrix:
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
- TARGET: i686-pc-windows-gnu
|
||||
|
||||
install:
|
||||
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
|
||||
- rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
|
||||
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
|
||||
- SET PATH=%PATH%;C:\MinGW\bin
|
||||
- rustc -V
|
||||
- cargo -V
|
||||
|
||||
build: false
|
||||
|
||||
test_script:
|
||||
- cargo build --verbose
|
|
@ -1,157 +0,0 @@
|
|||
//! This crate provides the following three functions:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # trait Ignore {
|
||||
//! fn stdin_isatty() -> bool
|
||||
//! # ;
|
||||
//! fn stdout_isatty() -> bool
|
||||
//! # ;
|
||||
//! fn stderr_isatty() -> bool
|
||||
//! # ;
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! On Linux and Mac they are implemented with [`libc::isatty`]. On Windows they
|
||||
//! are implemented with [`kernel32::GetConsoleMode`].
|
||||
//!
|
||||
//! [`libc::isatty`]: http://man7.org/linux/man-pages/man3/isatty.3.html
|
||||
//! [`kernel32::GetConsoleMode`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms683167.aspx
|
||||
//!
|
||||
//! The `stdin_isatty` function is not yet implemented for Windows. If you need
|
||||
//! it, please check [dtolnay/isatty#1] and contribute an implementation!
|
||||
//!
|
||||
//! [dtolnay/isatty#1]: https://github.com/dtolnay/isatty/issues/1
|
||||
//!
|
||||
//! ## Usage
|
||||
//!
|
||||
//! `Cargo.toml`
|
||||
//!
|
||||
//! > ```toml
|
||||
//! > [dependencies]
|
||||
//! > isatty = "0.1"
|
||||
//! > ```
|
||||
//!
|
||||
//! `src/main.rs`
|
||||
//!
|
||||
//! > ```rust
|
||||
//! > extern crate isatty;
|
||||
//! > use isatty::{stdin_isatty, stdout_isatty, stderr_isatty};
|
||||
//! >
|
||||
//! > fn main() {
|
||||
//! > println!("stdin: {}", stdin_isatty());
|
||||
//! > println!("stdout: {}", stdout_isatty());
|
||||
//! > println!("stderr: {}", stderr_isatty());
|
||||
//! > }
|
||||
//! > ```
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/isatty/0.1.5")]
|
||||
|
||||
// Based on:
|
||||
// - https://github.com/rust-lang/cargo/blob/099ad28104fe319f493dc42e0c694d468c65767d/src/cargo/lib.rs#L154-L178
|
||||
// - https://github.com/BurntSushi/ripgrep/issues/94#issuecomment-261761687
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn stdin_isatty() -> bool {
|
||||
isatty(stream::Stream::Stdin)
|
||||
}
|
||||
|
||||
pub fn stdout_isatty() -> bool {
|
||||
isatty(stream::Stream::Stdout)
|
||||
}
|
||||
|
||||
pub fn stderr_isatty() -> bool {
|
||||
isatty(stream::Stream::Stderr)
|
||||
}
|
||||
|
||||
mod stream {
|
||||
pub enum Stream {
|
||||
#[cfg(unix)]
|
||||
Stdin,
|
||||
Stdout,
|
||||
Stderr,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
use unix::isatty;
|
||||
#[cfg(unix)]
|
||||
mod unix {
|
||||
use stream::Stream;
|
||||
|
||||
pub fn isatty(stream: Stream) -> bool {
|
||||
extern crate libc;
|
||||
|
||||
let fd = match stream {
|
||||
Stream::Stdin => libc::STDIN_FILENO,
|
||||
Stream::Stdout => libc::STDOUT_FILENO,
|
||||
Stream::Stderr => libc::STDERR_FILENO,
|
||||
};
|
||||
|
||||
unsafe { libc::isatty(fd) != 0 }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
use windows::isatty;
|
||||
#[cfg(windows)]
|
||||
mod windows {
|
||||
extern crate kernel32;
|
||||
extern crate winapi;
|
||||
|
||||
use stream::Stream;
|
||||
|
||||
pub fn isatty(stream: Stream) -> bool {
|
||||
let handle = match stream {
|
||||
Stream::Stdout => winapi::winbase::STD_OUTPUT_HANDLE,
|
||||
Stream::Stderr => winapi::winbase::STD_ERROR_HANDLE,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let handle = kernel32::GetStdHandle(handle);
|
||||
|
||||
// check for msys/cygwin
|
||||
if is_cygwin_pty(handle) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let mut out = 0;
|
||||
kernel32::GetConsoleMode(handle, &mut out) != 0
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if there is an MSYS/cygwin tty on the given handle.
|
||||
fn is_cygwin_pty(handle: winapi::HANDLE) -> bool {
|
||||
use std::ffi::OsString;
|
||||
use std::mem;
|
||||
use std::os::raw::c_void;
|
||||
use std::os::windows::ffi::OsStringExt;
|
||||
use std::slice;
|
||||
|
||||
use self::kernel32::GetFileInformationByHandleEx;
|
||||
use self::winapi::fileapi::FILE_NAME_INFO;
|
||||
use self::winapi::minwinbase::FileNameInfo;
|
||||
use self::winapi::minwindef::MAX_PATH;
|
||||
|
||||
unsafe {
|
||||
let size = mem::size_of::<FILE_NAME_INFO>();
|
||||
let mut name_info_bytes = vec![0u8; size + MAX_PATH];
|
||||
let res = GetFileInformationByHandleEx(handle,
|
||||
FileNameInfo,
|
||||
&mut *name_info_bytes as *mut _ as *mut c_void,
|
||||
name_info_bytes.len() as u32);
|
||||
if res == 0 {
|
||||
return true;
|
||||
}
|
||||
let name_info: FILE_NAME_INFO = *(name_info_bytes[0..size]
|
||||
.as_ptr() as *const FILE_NAME_INFO);
|
||||
let name_bytes = &name_info_bytes[size..size + name_info.FileNameLength as usize];
|
||||
let name_u16 = slice::from_raw_parts(name_bytes.as_ptr() as *const u16,
|
||||
name_bytes.len() / 2);
|
||||
let name = OsString::from_wide(name_u16)
|
||||
.as_os_str()
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
name.contains("msys-") || name.contains("-pty")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
{"files":{".travis.yml":"4b02f83b1737cb2149dce4ceb26f0f2bb638ca82babfb343119c9fea0e472248","CHANGELOG.md":"0c6701474b807ee3738fa9d06ed9fbea7d07531b209a9da75fbf5bcf172f9b94","Cargo.toml":"1815b813a7345aea82031ed4e7c7b588fd1b3abc97c895421ce2374e7e97a763","LICENSE-MPL2":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","Makefile":"500a3af82638116a8d782b74091185fa7440b38cce99dd0b246e9965807d48b1","README.md":"3da4fe444a3d6052a721dc79930499b43155fee58460e2bd66d07d35a8f2abf7","examples/signal.rs":"799625fe867f896dddeb06a04049128b297526364414351f947976842a1b1405","lib.rs":"1ca3897552e020d754ff809367c0cbe3f9ece094f5a48a5002c94e7cb6340e67"},"package":"d6f5a4e4908d6818fe553b6126ba5377801556ab885c65ebf960b722a6778864"}
|
|
@ -1,25 +0,0 @@
|
|||
language: rust
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
|
||||
script:
|
||||
- make all
|
||||
- make travistest
|
||||
- if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then make bench ; fi
|
||||
|
||||
env:
|
||||
global:
|
||||
- RUST_BACKTRACE=1
|
||||
matrix:
|
||||
-
|
||||
- RELEASE=true
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/6d8e17dd2fa83b143168
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
on_failure: change # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
|
@ -1,10 +0,0 @@
|
|||
# Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 0.4.3 - 2016-11-30
|
||||
### Changed
|
||||
|
||||
* Moved to own repository
|
|
@ -1,25 +0,0 @@
|
|||
[package]
|
||||
name = "slog-atomic"
|
||||
version = "0.4.3"
|
||||
authors = ["Dawid Ciężarkiewicz <dpc@dpc.pw>"]
|
||||
description = "Atomic run-time controllable drain for slog-rs"
|
||||
keywords = ["slog", "logging", "log", "atomic"]
|
||||
license = "MPL-2.0"
|
||||
documentation = "https://docs.rs/slog-atomic"
|
||||
homepage = "https://github.com/slog-rs/slog"
|
||||
repository = "https://github.com/slog-rs/atomic"
|
||||
readme = "README.md"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
slog = "1"
|
||||
crossbeam = "0.2.9"
|
||||
|
||||
[dev-dependencies]
|
||||
lazy_static = "0.1.16"
|
||||
nix = "0.6.0"
|
||||
slog-term = "1"
|
||||
slog-json = "1"
|
||||
slog-stream = "1"
|
|
@ -1,373 +0,0 @@
|
|||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
|
@ -1,68 +0,0 @@
|
|||
PKG_NAME=$(shell grep name Cargo.toml | head -n 1 | awk -F \" '{print $$2}')
|
||||
DOCS_DEFAULT_MODULE=$(subst -,_,$(PKG_NAME))
|
||||
ifeq (, $(shell which cargo-check 2> /dev/null))
|
||||
DEFAULT_TARGET=build
|
||||
else
|
||||
DEFAULT_TARGET=build
|
||||
endif
|
||||
|
||||
default: $(DEFAULT_TARGET)
|
||||
|
||||
ALL_TARGETS += build $(EXAMPLES) test doc
|
||||
ifneq ($(RELEASE),)
|
||||
$(info RELEASE BUILD: $(PKG_NAME))
|
||||
CARGO_FLAGS += --release
|
||||
else
|
||||
$(info DEBUG BUILD: $(PKG_NAME); use `RELEASE=true make [args]` for release build)
|
||||
endif
|
||||
|
||||
EXAMPLES = $(shell cd examples 2>/dev/null && ls *.rs 2>/dev/null | sed -e 's/.rs$$//g' )
|
||||
|
||||
all: $(ALL_TARGETS)
|
||||
|
||||
.PHONY: run test build doc clean clippy
|
||||
run test build clean:
|
||||
cargo $@ $(CARGO_FLAGS)
|
||||
|
||||
check:
|
||||
$(info Running check; use `make build` to actually build)
|
||||
cargo $@ $(CARGO_FLAGS)
|
||||
|
||||
clippy:
|
||||
cargo build --features clippy
|
||||
|
||||
.PHONY: bench
|
||||
bench:
|
||||
cargo $@ $(filter-out --release,$(CARGO_FLAGS))
|
||||
|
||||
.PHONY: travistest
|
||||
travistest: test
|
||||
|
||||
.PHONY: longtest
|
||||
longtest:
|
||||
@echo "Running longtest. Press Ctrl+C to stop at any time"
|
||||
@sleep 2
|
||||
@i=0; while i=$$((i + 1)) && echo "Iteration $$i" && make test ; do :; done
|
||||
|
||||
.PHONY: $(EXAMPLES)
|
||||
$(EXAMPLES):
|
||||
cargo build --example $@ $(CARGO_FLAGS)
|
||||
|
||||
.PHONY: doc
|
||||
doc: FORCE
|
||||
cargo doc
|
||||
|
||||
.PHONY: publishdoc
|
||||
publishdoc:
|
||||
rm -rf target/doc
|
||||
make doc
|
||||
echo '<meta http-equiv="refresh" content="0;url='${DOCS_DEFAULT_MODULE}'/index.html">' > target/doc/index.html
|
||||
ghp-import -n target/doc
|
||||
git push -f origin gh-pages
|
||||
|
||||
.PHONY: docview
|
||||
docview: doc
|
||||
xdg-open target/doc/$(PKG_NAME)/index.html
|
||||
|
||||
.PHONY: FORCE
|
||||
FORCE:
|
|
@ -1,27 +0,0 @@
|
|||
<p align="center">
|
||||
|
||||
<a href="https://github.com/slog-rs/slog">
|
||||
<img src="https://cdn.rawgit.com/slog-rs/misc/master/media/slog.svg" alt="slog-rs logo">
|
||||
</a>
|
||||
<br>
|
||||
|
||||
<a href="https://travis-ci.org/slog-rs/atomic">
|
||||
<img src="https://img.shields.io/travis/slog-rs/atomic/master.svg" alt="Travis CI Build Status">
|
||||
</a>
|
||||
|
||||
<a href="https://crates.io/crates/slog-atomic">
|
||||
<img src="https://img.shields.io/crates/d/slog-atomic.svg" alt="slog-atomic on crates.io">
|
||||
</a>
|
||||
|
||||
<a href="https://gitter.im/slog-rs/slog">
|
||||
<img src="https://img.shields.io/gitter/room/slog-rs/slog.svg" alt="slog-rs Gitter Chat">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
# slog-atomic - Atomic run-time controllable drain for [slog-rs]
|
||||
|
||||
[slog-rs]: //github.com/slog-rs/slog
|
||||
|
||||
Using `slog-atomic` you can create a `slog::Drain` that can change behaviour
|
||||
in a thread-safe way, in runtime. This is useful eg. for triggering different
|
||||
logging levels from a signal handler.
|
|
@ -1,70 +0,0 @@
|
|||
#[macro_use]
|
||||
extern crate slog;
|
||||
extern crate slog_term;
|
||||
extern crate slog_atomic;
|
||||
extern crate slog_json;
|
||||
extern crate slog_stream;
|
||||
extern crate nix;
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
use nix::sys::signal;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::Ordering::SeqCst;
|
||||
use std::time::Duration;
|
||||
|
||||
use std::{thread, io};
|
||||
use slog::*;
|
||||
use slog_atomic::*;
|
||||
use slog_stream::*;
|
||||
|
||||
lazy_static! {
|
||||
// global atomic switch drain control
|
||||
static ref ATOMIC_DRAIN_SWITCH : AtomicSwitchCtrl<io::Error> = AtomicSwitch::new(
|
||||
Discard.map_err(|_| io::Error::new(io::ErrorKind::Other, "should no happen"))
|
||||
).ctrl();
|
||||
|
||||
// track current state of the atomic switch drain
|
||||
static ref ATOMIC_DRAIN_SWITCH_STATE : AtomicBool = AtomicBool::new(false);
|
||||
}
|
||||
|
||||
fn atomic_drain_switch() {
|
||||
// XXX: Not atomic. Race?
|
||||
let new = !ATOMIC_DRAIN_SWITCH_STATE.load(SeqCst);
|
||||
ATOMIC_DRAIN_SWITCH_STATE.store(new, SeqCst);
|
||||
|
||||
if new {
|
||||
ATOMIC_DRAIN_SWITCH.set(stream(io::stdout(), slog_json::default()))
|
||||
} else {
|
||||
ATOMIC_DRAIN_SWITCH.set(slog_term::streamer().full().stdout().build())
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn handle_sigusr1(_: i32) {
|
||||
atomic_drain_switch();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let sig_action = signal::SigAction::new(signal::SigHandler::Handler(handle_sigusr1),
|
||||
signal::SaFlags::empty(),
|
||||
signal::SigSet::empty());
|
||||
signal::sigaction(signal::SIGUSR1, &sig_action).unwrap();
|
||||
}
|
||||
|
||||
let drain = slog::duplicate(slog_term::streamer().stderr().full().build(), ATOMIC_DRAIN_SWITCH.drain()).fuse();
|
||||
|
||||
atomic_drain_switch();
|
||||
|
||||
let log = Logger::root(drain, o!());
|
||||
|
||||
info!(log, "logging a message every 3s");
|
||||
info!(log, "send SIGUSR1 signal to switch output with");
|
||||
let pid = nix::unistd::getpid();
|
||||
info!(log, "kill -SIGUSR1 {}", pid);
|
||||
loop {
|
||||
info!(log, "tick");
|
||||
thread::sleep(Duration::from_millis(3000));
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
//! Slog atomic switching drain
|
||||
//!
|
||||
//! `AtomicSwitch` allows swapping drain that it wraps atomically, race-free, in
|
||||
//! runtime. This can be useful eg. for turning on debug logging
|
||||
//! in production.
|
||||
//!
|
||||
//! See [`slog` `signal.rs`
|
||||
//! example](https://github.com/dpc/slog-rs/blob/master/examples/signal.rs)
|
||||
#![warn(missing_docs)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate slog;
|
||||
extern crate crossbeam;
|
||||
|
||||
use slog::*;
|
||||
use std::sync::Arc;
|
||||
use crossbeam::sync::ArcCell;
|
||||
|
||||
/// Handle to `AtomicSwitch` that controls it.
|
||||
pub struct AtomicSwitchCtrl<E>(Arc<ArcCell<Box<Drain<Error=E>+Send+Sync>>>);
|
||||
|
||||
/// Drain wrapping another drain, allowing atomic substitution in runtime
|
||||
pub struct AtomicSwitch<E>(Arc<ArcCell<Box<Drain<Error=E>+Send+Sync>>>);
|
||||
|
||||
impl<E> AtomicSwitch<E> {
|
||||
/// Wrap `drain` in `AtomicSwitch` to allow swapping it later
|
||||
///
|
||||
/// Use `AtomicSwitch::ctrl()` to get a handle to it
|
||||
pub fn new<D: Drain<Error=E> + 'static + Send+Sync>(drain: D) -> Self {
|
||||
AtomicSwitch::new_from_arc(Arc::new(ArcCell::new(Arc::new(Box::new(drain) as Box<Drain<Error=E>+Send+Sync>))))
|
||||
}
|
||||
|
||||
/// Create new `AtomicSwitch` from an existing `Arc<...>`
|
||||
///
|
||||
/// See `AtomicSwitch::new()`
|
||||
pub fn new_from_arc(d: Arc<ArcCell<Box<Drain<Error=E>+Send+Sync>>>) -> Self {
|
||||
AtomicSwitch(d)
|
||||
}
|
||||
|
||||
/// Get a `AtomicSwitchCtrl` handle to control this `AtomicSwitch` drain
|
||||
pub fn ctrl(&self) -> AtomicSwitchCtrl<E> {
|
||||
AtomicSwitchCtrl(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> AtomicSwitchCtrl<E> {
|
||||
/// Get Arc to the currently wrapped drain
|
||||
pub fn get(&self) -> Arc<Box<Drain<Error=E>+Send+Sync>> {
|
||||
self.0.get()
|
||||
}
|
||||
|
||||
/// Set the current wrapped drain
|
||||
pub fn set<D: Drain<Error=E>+Send+Sync>(&self, drain: D) {
|
||||
let _ = self.0.set(Arc::new(Box::new(drain)));
|
||||
}
|
||||
|
||||
/// Swap the existing drain with a new one
|
||||
pub fn swap(&self, drain: Arc<Box<Drain<Error=E>+Send+Sync>>) -> Arc<Box<Drain<Error=E>+Send+Sync>> {
|
||||
self.0.set(drain)
|
||||
}
|
||||
|
||||
/// Get a `AtomicSwitch` drain controlled by this `AtomicSwitchCtrl`
|
||||
pub fn drain(&self) -> AtomicSwitch<E> {
|
||||
AtomicSwitch(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> Drain for AtomicSwitch<E> {
|
||||
type Error = E;
|
||||
fn log(&self, info: &Record, logger_values: &OwnedKeyValueList) -> std::result::Result<(), E> {
|
||||
self.0.get().log(info, logger_values)
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
{"files":{".travis.yml":"4b02f83b1737cb2149dce4ceb26f0f2bb638ca82babfb343119c9fea0e472248","CHANGELOG.md":"4de7cbce3846d61e5063e5cc6c64db5fc1c6e0a63c3c4b30206a8441d4b63fef","Cargo.toml":"d3d3f41b9c410ddf2abe7eca75a7e04ed8a8e5d31234778a8dc0adb638e26cae","LICENSE-MPL2":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","Makefile":"500a3af82638116a8d782b74091185fa7440b38cce99dd0b246e9965807d48b1","README.md":"da16c3f07d252efcad1bfb5a31a01d9b21cb05771b928a84ec1b489b8d0cc373","lib.rs":"4cbd62e5b20c363f4f5232b307b7ba78f89141a2518ca1b110bab6c9f7657c8a"},"package":"511581f4dd1dc90e4eca99b60be8a692d9c975e8757558aa774f16007d27492a"}
|
|
@ -1,25 +0,0 @@
|
|||
language: rust
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
|
||||
script:
|
||||
- make all
|
||||
- make travistest
|
||||
- if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then make bench ; fi
|
||||
|
||||
env:
|
||||
global:
|
||||
- RUST_BACKTRACE=1
|
||||
matrix:
|
||||
-
|
||||
- RELEASE=true
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/6d8e17dd2fa83b143168
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
on_failure: change # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
|
@ -1,15 +0,0 @@
|
|||
# Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 0.1.2 - 2017-02-17
|
||||
### Changed
|
||||
|
||||
* Small fixes
|
||||
* Bumped versions of internal deps.
|
||||
|
||||
## 0.1.0 - 2016-10-20
|
||||
### Added
|
||||
* `Async` drain
|
|
@ -1,18 +0,0 @@
|
|||
[package]
|
||||
name = "slog-extra"
|
||||
version = "0.1.2"
|
||||
authors = ["Dawid Ciężarkiewicz <dpc@dpc.pw>"]
|
||||
description = "Standard slog-rs extensions"
|
||||
keywords = ["slog", "logging", "log"]
|
||||
license = "MPL-2.0"
|
||||
documentation = "https://docs.rs/slog-extra"
|
||||
homepage = "https://github.com/slog-rs/slog"
|
||||
repository = "https://github.com/slog-rs/extra"
|
||||
readme = "README.md"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
slog = "1.2.0"
|
||||
thread_local = { version = "0.3.2" }
|
|
@ -1,373 +0,0 @@
|
|||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
|
@ -1,68 +0,0 @@
|
|||
PKG_NAME=$(shell grep name Cargo.toml | head -n 1 | awk -F \" '{print $$2}')
|
||||
DOCS_DEFAULT_MODULE=$(subst -,_,$(PKG_NAME))
|
||||
ifeq (, $(shell which cargo-check 2> /dev/null))
|
||||
DEFAULT_TARGET=build
|
||||
else
|
||||
DEFAULT_TARGET=build
|
||||
endif
|
||||
|
||||
default: $(DEFAULT_TARGET)
|
||||
|
||||
ALL_TARGETS += build $(EXAMPLES) test doc
|
||||
ifneq ($(RELEASE),)
|
||||
$(info RELEASE BUILD: $(PKG_NAME))
|
||||
CARGO_FLAGS += --release
|
||||
else
|
||||
$(info DEBUG BUILD: $(PKG_NAME); use `RELEASE=true make [args]` for release build)
|
||||
endif
|
||||
|
||||
EXAMPLES = $(shell cd examples 2>/dev/null && ls *.rs 2>/dev/null | sed -e 's/.rs$$//g' )
|
||||
|
||||
all: $(ALL_TARGETS)
|
||||
|
||||
.PHONY: run test build doc clean clippy
|
||||
run test build clean:
|
||||
cargo $@ $(CARGO_FLAGS)
|
||||
|
||||
check:
|
||||
$(info Running check; use `make build` to actually build)
|
||||
cargo $@ $(CARGO_FLAGS)
|
||||
|
||||
clippy:
|
||||
cargo build --features clippy
|
||||
|
||||
.PHONY: bench
|
||||
bench:
|
||||
cargo $@ $(filter-out --release,$(CARGO_FLAGS))
|
||||
|
||||
.PHONY: travistest
|
||||
travistest: test
|
||||
|
||||
.PHONY: longtest
|
||||
longtest:
|
||||
@echo "Running longtest. Press Ctrl+C to stop at any time"
|
||||
@sleep 2
|
||||
@i=0; while i=$$((i + 1)) && echo "Iteration $$i" && make test ; do :; done
|
||||
|
||||
.PHONY: $(EXAMPLES)
|
||||
$(EXAMPLES):
|
||||
cargo build --example $@ $(CARGO_FLAGS)
|
||||
|
||||
.PHONY: doc
|
||||
doc: FORCE
|
||||
cargo doc
|
||||
|
||||
.PHONY: publishdoc
|
||||
publishdoc:
|
||||
rm -rf target/doc
|
||||
make doc
|
||||
echo '<meta http-equiv="refresh" content="0;url='${DOCS_DEFAULT_MODULE}'/index.html">' > target/doc/index.html
|
||||
ghp-import -n target/doc
|
||||
git push -f origin gh-pages
|
||||
|
||||
.PHONY: docview
|
||||
docview: doc
|
||||
xdg-open target/doc/$(PKG_NAME)/index.html
|
||||
|
||||
.PHONY: FORCE
|
||||
FORCE:
|
|
@ -1,23 +0,0 @@
|
|||
# slog-extra - Standard [slog-rs] extensions
|
||||
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/slog-rs/std">
|
||||
<img src="https://img.shields.io/travis/slog-rs/std/master.svg" alt="Travis CI Build Status">
|
||||
</a>
|
||||
|
||||
<a href="https://crates.io/crates/slog-std">
|
||||
<img src="https://img.shields.io/crates/d/slog-std.svg" alt="slog-std on crates.io">
|
||||
</a>
|
||||
|
||||
<a href="https://gitter.im/dpc/slog-std">
|
||||
<img src="https://img.shields.io/gitter/room/dpc/slog-rs.svg" alt="slog-rs Gitter Chat">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
[slog-rs]: //github.com/slog-rs/core
|
||||
|
||||
This crates contains slog-rs extensions that don't belong to the core `slog` crate due to:
|
||||
|
||||
* not supporting `no_std`
|
||||
* having additional dependencies
|
||||
* other problems
|
|
@ -1,237 +0,0 @@
|
|||
//! Standard slog-rs extensions.
|
||||
#![warn(missing_docs)]
|
||||
|
||||
extern crate slog;
|
||||
extern crate thread_local;
|
||||
|
||||
use slog::Drain;
|
||||
|
||||
use std::sync::{mpsc, Mutex};
|
||||
use std::fmt;
|
||||
use std::{io, thread};
|
||||
use slog::{Record, RecordStatic, Level};
|
||||
use slog::ser::{self, Serialize, Serializer};
|
||||
|
||||
use slog::OwnedKeyValueList;
|
||||
|
||||
|
||||
/// `Async` drain
|
||||
///
|
||||
/// `Async` will send all the logging records to a wrapped drain running in another thread.
|
||||
///
|
||||
/// Note: Dropping `Async` waits for it's worker-thread to finish (thus handle all previous
|
||||
/// requests). If you can't tolerate the delay, make sure you drop `Async` drain instance eg. in
|
||||
/// another thread.
|
||||
pub struct Async {
|
||||
ref_sender: Mutex<mpsc::Sender<AsyncMsg>>,
|
||||
tl_sender: thread_local::ThreadLocal<mpsc::Sender<AsyncMsg>>,
|
||||
join: Mutex<Option<thread::JoinHandle<()>>>,
|
||||
}
|
||||
|
||||
impl Async {
|
||||
/// Create `Async` drain
|
||||
///
|
||||
/// The wrapped drain must handle all error conditions (`Drain<Error=Never>`). See
|
||||
/// `slog::DrainExt::fuse()` and `slog::DrainExt::ignore_err()` for typical error handling
|
||||
/// strategies.
|
||||
pub fn new<D: slog::Drain<Error=slog::Never> + Send + 'static>(drain: D) -> Self {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let join = thread::spawn(move || {
|
||||
loop {
|
||||
match rx.recv().unwrap() {
|
||||
AsyncMsg::Record(r) => {
|
||||
let rs = RecordStatic {
|
||||
level: r.level,
|
||||
file: r.file,
|
||||
line: r.line,
|
||||
column: r.column,
|
||||
function: r.function,
|
||||
module: r.module,
|
||||
target: &r.target,
|
||||
};
|
||||
let record_values: Vec<_> = r.record_values
|
||||
.iter()
|
||||
.map(|&(k, ref v)| (k, v as &Serialize))
|
||||
.collect();
|
||||
|
||||
drain.log(
|
||||
&Record::new(&rs,
|
||||
format_args!("{}", r.msg),
|
||||
record_values.as_slice()
|
||||
),
|
||||
&r.logger_values
|
||||
).unwrap();
|
||||
}
|
||||
AsyncMsg::Finish => return,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Async{
|
||||
ref_sender: Mutex::new(tx),
|
||||
tl_sender: thread_local::ThreadLocal::new(),
|
||||
join: Mutex::new(Some(join)),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_sender(&self) -> &mpsc::Sender<AsyncMsg> {
|
||||
self.tl_sender.get_or(|| {
|
||||
// TODO: Change to `get_or_try` https://github.com/Amanieu/thread_local-rs/issues/2
|
||||
Box::new(self.ref_sender.lock().unwrap().clone())
|
||||
})
|
||||
}
|
||||
|
||||
/// Send `AsyncRecord` to a worker thread.
|
||||
fn send(&self, r: AsyncRecord) -> io::Result<()> {
|
||||
let sender = self.get_sender();
|
||||
|
||||
sender.send(AsyncMsg::Record(r))
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::BrokenPipe, "Send failed"))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type RecordValues = Vec<(&'static str, Box<Serialize + Send>)>;
|
||||
|
||||
struct ToSendSerializer {
|
||||
record_values: RecordValues,
|
||||
}
|
||||
|
||||
impl ToSendSerializer {
|
||||
fn new() -> Self {
|
||||
ToSendSerializer { record_values: Vec::new() }
|
||||
}
|
||||
|
||||
fn finish(self) -> RecordValues {
|
||||
self.record_values
|
||||
}
|
||||
}
|
||||
|
||||
impl Serializer for ToSendSerializer {
|
||||
fn emit_bool(&mut self, key: &'static str, val: bool) -> ser::Result {
|
||||
self.record_values.push((key, Box::new(val)));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_unit(&mut self, key: &'static str) -> ser::Result {
|
||||
self.record_values.push((key, Box::new(())));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_none(&mut self, key: &'static str) -> ser::Result {
|
||||
let val: Option<()> = None;
|
||||
self.record_values.push((key, Box::new(val)));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_char(&mut self, key: &'static str, val: char) -> ser::Result {
|
||||
self.record_values.push((key, Box::new(val)));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_u8(&mut self, key: &'static str, val: u8) -> ser::Result {
|
||||
self.record_values.push((key, Box::new(val)));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_i8(&mut self, key: &'static str, val: i8) -> ser::Result {
|
||||
self.record_values.push((key, Box::new(val)));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_u16(&mut self, key: &'static str, val: u16) -> ser::Result {
|
||||
self.record_values.push((key, Box::new(val)));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_i16(&mut self, key: &'static str, val: i16) -> ser::Result {
|
||||
self.record_values.push((key, Box::new(val)));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_u32(&mut self, key: &'static str, val: u32) -> ser::Result {
|
||||
self.record_values.push((key, Box::new(val)));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_i32(&mut self, key: &'static str, val: i32) -> ser::Result {
|
||||
self.record_values.push((key, Box::new(val)));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_f32(&mut self, key: &'static str, val: f32) -> ser::Result {
|
||||
self.record_values.push((key, Box::new(val)));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_u64(&mut self, key: &'static str, val: u64) -> ser::Result {
|
||||
self.record_values.push((key, Box::new(val)));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_i64(&mut self, key: &'static str, val: i64) -> ser::Result {
|
||||
self.record_values.push((key, Box::new(val)));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_f64(&mut self, key: &'static str, val: f64) -> ser::Result {
|
||||
self.record_values.push((key, Box::new(val)));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_usize(&mut self, key: &'static str, val: usize) -> ser::Result {
|
||||
self.record_values.push((key, Box::new(val)));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_isize(&mut self, key: &'static str, val: isize) -> ser::Result {
|
||||
self.record_values.push((key, Box::new(val)));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_str(&mut self, key: &'static str, val: &str) -> ser::Result {
|
||||
self.record_values.push((key, Box::new(String::from(val))));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_arguments(&mut self, key: &'static str, val: &fmt::Arguments) -> ser::Result {
|
||||
self.record_values.push((key, Box::new(fmt::format(*val))));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Drain for Async {
|
||||
type Error = io::Error;
|
||||
|
||||
fn log(&self, record: &Record, logger_values: &OwnedKeyValueList) -> io::Result<()> {
|
||||
|
||||
let mut ser = ToSendSerializer::new();
|
||||
for &(k, v) in record.values() {
|
||||
try!(v.serialize(record, k, &mut ser))
|
||||
}
|
||||
|
||||
self.send(AsyncRecord {
|
||||
msg: fmt::format(record.msg()),
|
||||
level: record.level(),
|
||||
file: record.file(),
|
||||
line: record.line(),
|
||||
column: record.column(),
|
||||
function: record.function(),
|
||||
module: record.module(),
|
||||
target: String::from(record.target()),
|
||||
logger_values: logger_values.clone(),
|
||||
record_values: ser.finish(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct AsyncRecord {
|
||||
msg: String,
|
||||
level: Level,
|
||||
file: &'static str,
|
||||
line: u32,
|
||||
column: u32,
|
||||
function: &'static str,
|
||||
module: &'static str,
|
||||
target: String,
|
||||
logger_values: OwnedKeyValueList,
|
||||
record_values: Vec<(&'static str, Box<Serialize + Send>)>,
|
||||
}
|
||||
|
||||
enum AsyncMsg {
|
||||
Record(AsyncRecord),
|
||||
Finish,
|
||||
}
|
||||
|
||||
impl Drop for Async {
|
||||
fn drop(&mut self) {
|
||||
let sender = self.get_sender();
|
||||
|
||||
let _ = sender.send(AsyncMsg::Finish);
|
||||
let _ = self.join.lock().unwrap().take().unwrap().join();
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
{"files":{"CHANGELOG.md":"af163c2e549e8f0afa1a9045aa1a9a9f75d0c76eef19a9e13d696751a4befb67","Cargo.toml":"8db2e82b704d6b92c1a63723c5d2ec684fd60745d0706908dbe5d259a61c67a6","lib.rs":"bfffab260c34f0714054d51d2ac3a7fd0cd127fe07059d9327b988599408b8f0"},"package":"56cc08f40c45e0ab41dcfde0a19a22c5b7176d3827fc7d078450ebfdc080a37c"}
|
|
@ -1,21 +0,0 @@
|
|||
# Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 1.1.0
|
||||
### Changed
|
||||
|
||||
* BREAKING: Rewrite handling of owned values.
|
||||
|
||||
## 1.0.1 - 2016-10-02
|
||||
### Changed
|
||||
|
||||
* Fixed `StdLog` not serializing the key-value pairs.
|
||||
* `StdLog` message to `log` crate is lazily-evaluated.
|
||||
|
||||
|
||||
## 1.0.0 - 2016-09-21
|
||||
|
||||
First stable release.
|
|
@ -1,21 +0,0 @@
|
|||
[package]
|
||||
name = "slog-stdlog"
|
||||
version = "1.1.0"
|
||||
authors = ["Dawid Ciężarkiewicz <dpc@dpc.pw>"]
|
||||
description = "Standard Rust log crate adapter to slog-rs"
|
||||
keywords = ["slog", "logging", "json", "log"]
|
||||
license = "MPL-2.0"
|
||||
documentation = "https://dpc.github.io/slog-rs/"
|
||||
homepage = "https://github.com/dpc/slog-rs"
|
||||
repository = "https://github.com/dpc/slog-rs"
|
||||
readme = "../../README.md"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
slog = { version = "1.1", path = "../.." }
|
||||
slog-term = { version = "1", path = "../term" }
|
||||
log = "0.3.6"
|
||||
lazy_static = "0.2.1"
|
||||
crossbeam = "0.2.9"
|
|
@ -1,430 +0,0 @@
|
|||
//! Standard Rust log crate adapter to slog-rs
|
||||
//!
|
||||
//! This crate allows using `slog` features with code
|
||||
//! using legacy `log` statements.
|
||||
//!
|
||||
//! `log` crate expects a global logger to be registered
|
||||
//! (popular one is `env_logger`) as a handler for all
|
||||
//! `info!(...)` and similar.
|
||||
//!
|
||||
//! `slog-stdlog` will register itself as `log` global handler and forward all
|
||||
//! legacy logging statements to `slog`'s `Logger`. That means existing logging
|
||||
//! `debug!` (even in dependencies crates) work and utilize `slog` composable
|
||||
//! drains.
|
||||
//!
|
||||
//! See `init()` documentation for minimal working example.
|
||||
//!
|
||||
//! Note: Whilte `slog-scope` provides a similiar functionality, the `slog-scope` and `slog-stdlog`
|
||||
//! keep track of distinct logginc scopes.
|
||||
#![warn(missing_docs)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate slog;
|
||||
extern crate slog_term;
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate crossbeam;
|
||||
|
||||
use slog::{DrainExt, ser};
|
||||
|
||||
use log::LogMetadata;
|
||||
use std::sync::Arc;
|
||||
use std::cell::RefCell;
|
||||
use std::{io, fmt};
|
||||
use std::io::Write;
|
||||
|
||||
use slog::Level;
|
||||
use crossbeam::sync::ArcCell;
|
||||
|
||||
thread_local! {
|
||||
static TL_SCOPES: RefCell<Vec<slog::Logger>> = RefCell::new(Vec::with_capacity(8))
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref GLOBAL_LOGGER : ArcCell<slog::Logger> = ArcCell::new(
|
||||
Arc::new(
|
||||
slog::Logger::root(slog::Discard, o!())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
fn set_global_logger(l: slog::Logger) {
|
||||
let _ = GLOBAL_LOGGER.set(Arc::new(l));
|
||||
}
|
||||
|
||||
struct Logger;
|
||||
|
||||
|
||||
fn log_to_slog_level(level: log::LogLevel) -> Level {
|
||||
match level {
|
||||
log::LogLevel::Trace => Level::Trace,
|
||||
log::LogLevel::Debug => Level::Debug,
|
||||
log::LogLevel::Info => Level::Info,
|
||||
log::LogLevel::Warn => Level::Warning,
|
||||
log::LogLevel::Error => Level::Error,
|
||||
}
|
||||
}
|
||||
|
||||
impl log::Log for Logger {
|
||||
fn enabled(&self, _: &LogMetadata) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn log(&self, r: &log::LogRecord) {
|
||||
let level = log_to_slog_level(r.metadata().level());
|
||||
|
||||
let args = r.args();
|
||||
let target = r.target();
|
||||
let module = r.location().__module_path;
|
||||
let file = r.location().__file;
|
||||
let line = r.location().line();
|
||||
with_current_logger(|l| {
|
||||
let s = slog::RecordStatic {
|
||||
level: level,
|
||||
file: file,
|
||||
line: line,
|
||||
column: 0,
|
||||
function: "",
|
||||
module: module,
|
||||
target: target,
|
||||
};
|
||||
l.log(&slog::Record::new(&s, *args, &[]))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Set a `slog::Logger` as a global `log` create handler
|
||||
///
|
||||
/// This will forward all `log` records to `slog` logger.
|
||||
///
|
||||
/// ```
|
||||
/// // only use `o` macro from `slog` crate
|
||||
/// #[macro_use(o)]
|
||||
/// extern crate slog;
|
||||
/// #[macro_use]
|
||||
/// extern crate log;
|
||||
/// extern crate slog_stdlog;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let root = slog::Logger::root(
|
||||
/// slog::Discard,
|
||||
/// o!("build-id" => "8dfljdf"),
|
||||
/// );
|
||||
/// slog_stdlog::set_logger(root).unwrap();
|
||||
/// // Note: this `info!(...)` macro comes from `log` crate
|
||||
/// info!("standard logging redirected to slog");
|
||||
/// }
|
||||
/// ```
|
||||
pub fn set_logger(logger: slog::Logger) -> Result<(), log::SetLoggerError> {
|
||||
log::set_logger(|max_log_level| {
|
||||
max_log_level.set(log::LogLevelFilter::max());
|
||||
set_global_logger(logger);
|
||||
Box::new(Logger)
|
||||
})
|
||||
}
|
||||
|
||||
/// Set a `slog::Logger` as a global `log` create handler
|
||||
///
|
||||
/// This will forward `log` records that satisfy `log_level_filter` to `slog` logger.
|
||||
pub fn set_logger_level(logger: slog::Logger,
|
||||
log_level_filter: log::LogLevelFilter)
|
||||
-> Result<(), log::SetLoggerError> {
|
||||
log::set_logger(|max_log_level| {
|
||||
max_log_level.set(log_level_filter);
|
||||
set_global_logger(logger);
|
||||
Box::new(Logger)
|
||||
})
|
||||
}
|
||||
|
||||
/// Minimal initialization with default drain
|
||||
///
|
||||
/// The exact default drain is unspecified and will
|
||||
/// change in future versions! Use `set_logger` instead
|
||||
/// to build customized drain.
|
||||
///
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate log;
|
||||
/// extern crate slog_stdlog;
|
||||
///
|
||||
/// fn main() {
|
||||
/// slog_stdlog::init().unwrap();
|
||||
/// // Note: this `info!(...)` macro comes from `log` crate
|
||||
/// info!("standard logging redirected to slog");
|
||||
/// }
|
||||
/// ```
|
||||
pub fn init() -> Result<(), log::SetLoggerError> {
|
||||
let drain = slog::level_filter(Level::Info, slog_term::streamer().compact().build());
|
||||
set_logger(slog::Logger::root(drain.fuse(), o!()))
|
||||
}
|
||||
|
||||
struct ScopeGuard;
|
||||
|
||||
|
||||
impl ScopeGuard {
|
||||
fn new(logger: slog::Logger) -> Self {
|
||||
TL_SCOPES.with(|s| {
|
||||
s.borrow_mut().push(logger);
|
||||
});
|
||||
|
||||
ScopeGuard
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ScopeGuard {
|
||||
fn drop(&mut self) {
|
||||
TL_SCOPES.with(|s| {
|
||||
s.borrow_mut().pop().expect("TL_SCOPES should contain a logger");
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Access the currently active logger
|
||||
///
|
||||
/// The reference logger will be either:
|
||||
/// * global logger, or
|
||||
/// * currently active scope logger
|
||||
///
|
||||
/// **Warning**: Calling `scope` inside `f`
|
||||
/// will result in a panic.
|
||||
pub fn with_current_logger<F, R>(f: F) -> R
|
||||
where F: FnOnce(&slog::Logger) -> R
|
||||
{
|
||||
TL_SCOPES.with(|s| {
|
||||
let s = s.borrow();
|
||||
if s.is_empty() {
|
||||
f(&GLOBAL_LOGGER.get())
|
||||
} else {
|
||||
f(&s[s.len() - 1])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Access the `Logger` for the current logging scope
|
||||
pub fn logger() -> slog::Logger {
|
||||
TL_SCOPES.with(|s| {
|
||||
let s = s.borrow();
|
||||
if s.is_empty() {
|
||||
(*GLOBAL_LOGGER.get()).clone()
|
||||
} else {
|
||||
s[s.len() - 1].clone()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Execute code in a logging scope
|
||||
///
|
||||
/// Logging scopes allow using different logger for legacy logging
|
||||
/// statements in part of the code.
|
||||
///
|
||||
/// Logging scopes can be nested and are panic safe.
|
||||
///
|
||||
/// `logger` is the `Logger` to use during the duration of `f`.
|
||||
/// `with_current_logger` can be used to build it as a child of currently active
|
||||
/// logger.
|
||||
///
|
||||
/// `f` is a code to be executed in the logging scope.
|
||||
///
|
||||
/// Note: Thread scopes are thread-local. Each newly spawned thread starts
|
||||
/// with a global logger, as a current logger.
|
||||
pub fn scope<SF, R>(logger: slog::Logger, f: SF) -> R
|
||||
where SF: FnOnce() -> R
|
||||
{
|
||||
let _guard = ScopeGuard::new(logger);
|
||||
f()
|
||||
}
|
||||
|
||||
/// Drain logging `Record`s into `log` crate
|
||||
///
|
||||
/// Using `StdLog` is effectively the same as using `log::info!(...)` and
|
||||
/// other standard logging statements.
|
||||
///
|
||||
/// Caution needs to be taken to prevent circular loop where `Logger`
|
||||
/// installed via `slog-stdlog::set_logger` would log things to a `StdLog`
|
||||
/// drain, which would again log things to the global `Logger` and so on
|
||||
/// leading to an infinite recursion.
|
||||
pub struct StdLog;
|
||||
|
||||
struct LazyLogString<'a> {
|
||||
info: &'a slog::Record<'a>,
|
||||
logger_values : &'a slog::OwnedKeyValueList
|
||||
}
|
||||
|
||||
impl<'a> LazyLogString<'a> {
|
||||
|
||||
fn new(info : &'a slog::Record, logger_values : &'a slog::OwnedKeyValueList) -> Self {
|
||||
|
||||
LazyLogString {
|
||||
info: info,
|
||||
logger_values: logger_values,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for LazyLogString<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
||||
try!(write!(f, "{}", self.info.msg()));
|
||||
|
||||
let io = io::Cursor::new(Vec::new());
|
||||
let mut ser = KSV::new(io, ": ".into());
|
||||
|
||||
let res = {
|
||||
|| -> io::Result<()> {
|
||||
|
||||
for (ref k, ref v) in self.logger_values.iter() {
|
||||
try!(ser.io().write_all(", ".as_bytes()));
|
||||
try!(v.serialize(self.info, k, &mut ser));
|
||||
}
|
||||
|
||||
for &(ref k, ref v) in self.info.values().iter() {
|
||||
try!(ser.io().write_all(", ".as_bytes()));
|
||||
try!(v.serialize(self.info, k, &mut ser));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}().map_err(|_| fmt::Error);
|
||||
|
||||
try!(res);
|
||||
|
||||
let values = ser.into_inner().into_inner();
|
||||
|
||||
|
||||
write!(f, "{}", String::from_utf8_lossy(&values))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
impl slog::Drain for StdLog {
|
||||
type Error = io::Error;
|
||||
fn log(&self, info: &slog::Record, logger_values : &slog::OwnedKeyValueList) -> io::Result<()> {
|
||||
|
||||
let level = match info.level() {
|
||||
slog::Level::Critical => log::LogLevel::Error,
|
||||
slog::Level::Error => log::LogLevel::Error,
|
||||
slog::Level::Warning => log::LogLevel::Warn,
|
||||
slog::Level::Info => log::LogLevel::Info,
|
||||
slog::Level::Debug => log::LogLevel::Debug,
|
||||
slog::Level::Trace => log::LogLevel::Trace,
|
||||
};
|
||||
|
||||
let target = info.target();
|
||||
|
||||
let location = log::LogLocation {
|
||||
__module_path: info.module(),
|
||||
__file: info.file(),
|
||||
__line: info.line(),
|
||||
};
|
||||
|
||||
let lazy = LazyLogString::new(info, logger_values);
|
||||
// Please don't yell at me for this! :D
|
||||
// https://github.com/rust-lang-nursery/log/issues/95
|
||||
log::__log(level, target, &location, format_args!("{}", lazy));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Key-Separator-Value serializer
|
||||
struct KSV<W: io::Write> {
|
||||
separator: String,
|
||||
io: W,
|
||||
}
|
||||
|
||||
impl<W: io::Write> KSV<W> {
|
||||
fn new(io: W, separator: String) -> Self {
|
||||
KSV {
|
||||
io: io,
|
||||
separator: separator,
|
||||
}
|
||||
}
|
||||
|
||||
fn io(&mut self) -> &mut W {
|
||||
&mut self.io
|
||||
}
|
||||
|
||||
fn into_inner(self) -> W {
|
||||
self.io
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: io::Write> ser::Serializer for KSV<W> {
|
||||
fn emit_none(&mut self, key: &str) -> ser::Result {
|
||||
try!(write!(self.io, "{}{}{}", key, self.separator, "None"));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_unit(&mut self, key: &str) -> ser::Result {
|
||||
try!(write!(self.io, "{}", key));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn emit_bool(&mut self, key: &str, val: bool) -> ser::Result {
|
||||
try!(write!(self.io, "{}{}{}", key, self.separator, val));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn emit_char(&mut self, key: &str, val: char) -> ser::Result {
|
||||
try!(write!(self.io, "{}{}{}", key, self.separator, val));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn emit_usize(&mut self, key: &str, val: usize) -> ser::Result {
|
||||
try!(write!(self.io, "{}{}{}", key, self.separator, val));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_isize(&mut self, key: &str, val: isize) -> ser::Result {
|
||||
try!(write!(self.io, "{}{}{}", key, self.separator, val));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn emit_u8(&mut self, key: &str, val: u8) -> ser::Result {
|
||||
try!(write!(self.io, "{}{}{}", key, self.separator, val));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_i8(&mut self, key: &str, val: i8) -> ser::Result {
|
||||
try!(write!(self.io, "{}{}{}", key, self.separator, val));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_u16(&mut self, key: &str, val: u16) -> ser::Result {
|
||||
try!(write!(self.io, "{}{}{}", key, self.separator, val));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_i16(&mut self, key: &str, val: i16) -> ser::Result {
|
||||
try!(write!(self.io, "{}{}{}", key, self.separator, val));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_u32(&mut self, key: &str, val: u32) -> ser::Result {
|
||||
try!(write!(self.io, "{}{}{}", key, self.separator, val));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_i32(&mut self, key: &str, val: i32) -> ser::Result {
|
||||
try!(write!(self.io, "{}{}{}", key, self.separator, val));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_f32(&mut self, key: &str, val: f32) -> ser::Result {
|
||||
try!(write!(self.io, "{}{}{}", key, self.separator, val));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_u64(&mut self, key: &str, val: u64) -> ser::Result {
|
||||
try!(write!(self.io, "{}{}{}", key, self.separator, val));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_i64(&mut self, key: &str, val: i64) -> ser::Result {
|
||||
try!(write!(self.io, "{}{}{}", key, self.separator, val));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_f64(&mut self, key: &str, val: f64) -> ser::Result {
|
||||
try!(write!(self.io, "{}{}{}", key, self.separator, val));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_str(&mut self, key: &str, val: &str) -> ser::Result {
|
||||
try!(write!(self.io, "{}{}{}", key, self.separator, val));
|
||||
Ok(())
|
||||
}
|
||||
fn emit_arguments(&mut self, key: &str, val: &fmt::Arguments) -> ser::Result {
|
||||
try!(write!(self.io, "{}{}{}", key, self.separator, val));
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
{"files":{".travis.yml":"abf49e9a9c5e47bccf61fc38a27486fa13ca5dd39eeffab145c072418bbd98aa","CHANGELOG.md":"aca50d5d669b3414a45410e8ff53f9a98761a149b81262f012884035fb619b90","Cargo.toml":"6a799822989ca386b272fd0982adc749401fb0df3fec6a6a9da501d15ff72fc7","LICENSE-MPL2":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","Makefile":"500a3af82638116a8d782b74091185fa7440b38cce99dd0b246e9965807d48b1","README.md":"40005693579af3edb05aa440b675094cbec955e62eeb0fe5ee43fc5fc47e99fa","format.rs":"1655b17acb3c94f3c5b20bc881de192e57d0570ba372fbd62f4b3d013a5b17ba","lib.rs":"90f57f61cc9ecc1f88f8b6fcbcc76fa4fbd15537be24e410879c50da20e9c9c5","rusty-tags.vi":"f939543b8f86aba0015d7d10be2a6786bb1a8ae3eef7ef4ff248739d8c4d4716"},"package":"3fac4af71007ddb7338f771e059a46051f18d1454d8ac556f234a0573e719daa"}
|
|
@ -1,30 +0,0 @@
|
|||
language: rust
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq graphviz
|
||||
|
||||
script:
|
||||
- make all
|
||||
- make travistest
|
||||
- if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then make bench ; fi
|
||||
- if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then cargo build --no-default-features; fi
|
||||
|
||||
env:
|
||||
global:
|
||||
- RUST_BACKTRACE=1
|
||||
matrix:
|
||||
-
|
||||
- RELEASE=true
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/87a331e1a21456b6e2ad
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
on_failure: change # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
|
@ -1,34 +0,0 @@
|
|||
# Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 1.2.1 - 2017-05-10
|
||||
### Changed
|
||||
|
||||
* Update dependencies
|
||||
|
||||
## 1.1.0 - 2016-09-28
|
||||
### Changed
|
||||
|
||||
* **BREAKING**: `RecordDecorator` API has been changed to allow formatting
|
||||
without any allocation.
|
||||
|
||||
## 1.0.0 - 2016-09-21
|
||||
|
||||
First stable release.
|
||||
## 1.2.0 - [Unreleased]
|
||||
### Changed
|
||||
|
||||
* **BREAKING**: Switched `AsyncStramer` to `slog_extra::Async`
|
||||
|
||||
## 1.1.0 - 2016-09-28
|
||||
### Changed
|
||||
|
||||
* **BREAKING**: `RecordDecorator` API has been changed to allow formatting
|
||||
without any allocation.
|
||||
|
||||
## 1.0.0 - 2016-09-21
|
||||
|
||||
First stable release.
|
|
@ -1,19 +0,0 @@
|
|||
[package]
|
||||
name = "slog-stream"
|
||||
version = "1.2.1"
|
||||
authors = ["Dawid Ciężarkiewicz <dpc@dpc.pw>"]
|
||||
description = "`io::Write` streamer for slog-rs"
|
||||
keywords = ["log", "logging", "structured", "hierarchical", "stream"]
|
||||
license = "MPL-2.0"
|
||||
documentation = "https://docs.rs/slog-stream"
|
||||
homepage = "https://github.com/slog-rs/slog"
|
||||
repository = "https://github.com/slog-rs/stream"
|
||||
readme = "README.md"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
slog = "1.2"
|
||||
slog-extra = "0.1.1"
|
||||
thread_local = "0.3.2"
|
|
@ -1,373 +0,0 @@
|
|||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
|
@ -1,68 +0,0 @@
|
|||
PKG_NAME=$(shell grep name Cargo.toml | head -n 1 | awk -F \" '{print $$2}')
|
||||
DOCS_DEFAULT_MODULE=$(subst -,_,$(PKG_NAME))
|
||||
ifeq (, $(shell which cargo-check 2> /dev/null))
|
||||
DEFAULT_TARGET=build
|
||||
else
|
||||
DEFAULT_TARGET=build
|
||||
endif
|
||||
|
||||
default: $(DEFAULT_TARGET)
|
||||
|
||||
ALL_TARGETS += build $(EXAMPLES) test doc
|
||||
ifneq ($(RELEASE),)
|
||||
$(info RELEASE BUILD: $(PKG_NAME))
|
||||
CARGO_FLAGS += --release
|
||||
else
|
||||
$(info DEBUG BUILD: $(PKG_NAME); use `RELEASE=true make [args]` for release build)
|
||||
endif
|
||||
|
||||
EXAMPLES = $(shell cd examples 2>/dev/null && ls *.rs 2>/dev/null | sed -e 's/.rs$$//g' )
|
||||
|
||||
all: $(ALL_TARGETS)
|
||||
|
||||
.PHONY: run test build doc clean clippy
|
||||
run test build clean:
|
||||
cargo $@ $(CARGO_FLAGS)
|
||||
|
||||
check:
|
||||
$(info Running check; use `make build` to actually build)
|
||||
cargo $@ $(CARGO_FLAGS)
|
||||
|
||||
clippy:
|
||||
cargo build --features clippy
|
||||
|
||||
.PHONY: bench
|
||||
bench:
|
||||
cargo $@ $(filter-out --release,$(CARGO_FLAGS))
|
||||
|
||||
.PHONY: travistest
|
||||
travistest: test
|
||||
|
||||
.PHONY: longtest
|
||||
longtest:
|
||||
@echo "Running longtest. Press Ctrl+C to stop at any time"
|
||||
@sleep 2
|
||||
@i=0; while i=$$((i + 1)) && echo "Iteration $$i" && make test ; do :; done
|
||||
|
||||
.PHONY: $(EXAMPLES)
|
||||
$(EXAMPLES):
|
||||
cargo build --example $@ $(CARGO_FLAGS)
|
||||
|
||||
.PHONY: doc
|
||||
doc: FORCE
|
||||
cargo doc
|
||||
|
||||
.PHONY: publishdoc
|
||||
publishdoc:
|
||||
rm -rf target/doc
|
||||
make doc
|
||||
echo '<meta http-equiv="refresh" content="0;url='${DOCS_DEFAULT_MODULE}'/index.html">' > target/doc/index.html
|
||||
ghp-import -n target/doc
|
||||
git push -f origin gh-pages
|
||||
|
||||
.PHONY: docview
|
||||
docview: doc
|
||||
xdg-open target/doc/$(PKG_NAME)/index.html
|
||||
|
||||
.PHONY: FORCE
|
||||
FORCE:
|
|
@ -1,17 +0,0 @@
|
|||
## slog-stream - `io::Write` streamer for [slog-rs]
|
||||
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/slog-rs/stream">
|
||||
<img src="https://img.shields.io/travis/slog-rs/stream/master.svg" alt="Travis CI Build Status">
|
||||
</a>
|
||||
|
||||
<a href="https://crates.io/crates/slog-stream">
|
||||
<img src="https://img.shields.io/crates/d/slog-stream.svg" alt="slog-stream on crates.io">
|
||||
</a>
|
||||
|
||||
<a href="https://gitter.im/slog-rs/slog">
|
||||
<img src="https://img.shields.io/gitter/room/slog-rs/slog.svg" alt="slog-rs Gitter Chat">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
[slog-rs]: //github.com/slog-rs/slog
|
|
@ -1,53 +0,0 @@
|
|||
|
||||
/// Formats `Record`-s into IO
|
||||
pub trait Format: Send + Sync + Sized {
|
||||
/// Format one logging record and write into `io`
|
||||
fn format(&self,
|
||||
io: &mut io::Write,
|
||||
info: &Record,
|
||||
logger_values: &OwnedKeyValueList)
|
||||
-> io::Result<()>;
|
||||
}
|
||||
|
||||
/// Formatted stream decorator
|
||||
///
|
||||
/// Some `Format`s for which it make sense can use this to parametrize
|
||||
/// themselves on the exact behavior of formatting parts of the output. This
|
||||
/// can be used eg. to use color when displaying logger records on the terminal.
|
||||
pub trait Decorator: Send + Sync + Sized {
|
||||
/// Per-record decorator
|
||||
type RecordDecorator: RecordDecorator;
|
||||
|
||||
/// Get a `RecordDecorator` for a given `record`
|
||||
fn decorate(&self, record: &Record) -> Self::RecordDecorator;
|
||||
}
|
||||
|
||||
/// Per-record decorator
|
||||
// TODO 2.0: Make everything take `&mut self`.
|
||||
// TODO 2.0: Make everything take `f: &FnOnce`
|
||||
pub trait RecordDecorator {
|
||||
/// Format a field
|
||||
fn fmt_msg(&self, io: &mut io::Write, f: &Fn(&mut io::Write) -> io::Result<()>) -> io::Result<()> {
|
||||
f(io)
|
||||
}
|
||||
/// Format a key
|
||||
fn fmt_key(&self, io: &mut io::Write, f: &Fn(&mut io::Write) -> io::Result<()>) -> io::Result<()> {
|
||||
f(io)
|
||||
}
|
||||
/// Format a separator
|
||||
fn fmt_separator(&self, io: &mut io::Write, f: &Fn(&mut io::Write) -> io::Result<()>) -> io::Result<()> {
|
||||
f(io)
|
||||
}
|
||||
/// Format a value
|
||||
fn fmt_value(&self, io: &mut io::Write, f: &Fn(&mut io::Write) -> io::Result<()>) -> io::Result<()> {
|
||||
f(io)
|
||||
}
|
||||
/// Format a timestamp
|
||||
fn fmt_timestamp(&self, io: &mut io::Write, f : &Fn(&mut io::Write) -> io::Result<()>) -> io::Result<()> {
|
||||
f(io)
|
||||
}
|
||||
/// Format a level
|
||||
fn fmt_level(&self, io: &mut io::Write, f: &Fn(&mut io::Write) -> io::Result<()>) -> io::Result<()> {
|
||||
f(io)
|
||||
}
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
//! `io::Write` streamer for slog-rs
|
||||
//!
|
||||
//! One of the main drains not included in the core `slog-rs` create.
|
||||
//! `Streamer` drain serializes logging records into stream of bytes
|
||||
//! using given `Format` and writes it to a given `io::Write`.
|
||||
#![warn(missing_docs)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate slog;
|
||||
extern crate slog_extra;
|
||||
extern crate thread_local;
|
||||
|
||||
use slog::{Drain, DrainExt};
|
||||
|
||||
use std::cell::RefCell;
|
||||
|
||||
use std::sync::Mutex;
|
||||
use std::io;
|
||||
use slog::Record;
|
||||
|
||||
use slog_extra::Async;
|
||||
use slog::OwnedKeyValueList;
|
||||
|
||||
include!("format.rs");
|
||||
|
||||
thread_local! {
|
||||
static TL_BUF: RefCell<Vec<u8>> = RefCell::new(Vec::with_capacity(128))
|
||||
}
|
||||
|
||||
/// Drain formating records and writing them to a byte-stream (`io::Write`)
|
||||
///
|
||||
/// Uses mutex to serialize writes to `io`. Use `AsyncStreamer` for better
|
||||
/// performance, but without guarantee of immediate output.
|
||||
pub struct Streamer<W: io::Write, F: Format> {
|
||||
io: Mutex<W>,
|
||||
format: F,
|
||||
}
|
||||
|
||||
impl<W: io::Write, F: Format> Streamer<W, F> {
|
||||
/// Create new `Streamer` writing to `io` using `format`
|
||||
pub fn new(io: W, format: F) -> Self {
|
||||
Streamer {
|
||||
io: Mutex::new(io),
|
||||
format: format,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: 'static + io::Write + Send, F: Format + Send> Drain for Streamer<W, F> {
|
||||
type Error = io::Error;
|
||||
|
||||
fn log(&self, info: &Record, logger_values: &OwnedKeyValueList) -> io::Result<()> {
|
||||
|
||||
TL_BUF.with(|buf| {
|
||||
let mut buf = buf.borrow_mut();
|
||||
let res = {
|
||||
|| {
|
||||
try!(self.format.format(&mut *buf, info, logger_values));
|
||||
{
|
||||
let mut io = try!(self.io
|
||||
.lock()
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::Other, "lock error")));
|
||||
try!(io.write_all(&buf));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}();
|
||||
buf.clear();
|
||||
res
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Stream logging records to IO
|
||||
///
|
||||
/// Create `Streamer` drain
|
||||
pub fn stream<W: io::Write + Send, F: Format>(io: W, format: F) -> Streamer<W, F> {
|
||||
Streamer::new(io, format)
|
||||
}
|
||||
|
||||
/// Stream logging records to IO asynchronously
|
||||
///
|
||||
/// Create `AsyncStreamer` drain
|
||||
pub fn async_stream<W: io::Write + Send + 'static, F: Format + Send + 'static>(io: W,
|
||||
format: F)
|
||||
-> Async {
|
||||
Async::new(Streamer::new(io, format).fuse())
|
||||
}
|
|
@ -1,341 +0,0 @@
|
|||
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
|
||||
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
||||
ASCII_LOWERCASE_MAP /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^static ASCII_LOWERCASE_MAP: [u8; 256] = [$/;" c
|
||||
AsFmtSerializer /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^pub struct AsFmtSerializer<F>(pub F)$/;" s
|
||||
Async /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^impl Async {$/;" i
|
||||
Async /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^pub struct Async {$/;" s
|
||||
AsyncMsg /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^enum AsyncMsg {$/;" g
|
||||
AsyncRecord /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^struct AsyncRecord {$/;" s
|
||||
BoxExt /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^trait BoxExt<T: ?Sized> {$/;" t
|
||||
BoxExt for Box /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T: ?Sized> BoxExt<T> for Box<T> {$/;" i
|
||||
CachedIntoIter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^pub type CachedIntoIter<T> = Chain<OptionIter<Box<T>>, IntoIter<T>>;$/;" T
|
||||
CachedIterMut /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^pub type CachedIterMut<'a, T> = Chain<OptionIter<&'a mut Box<T>>, IterMut<'a, T>>;$/;" T
|
||||
CachedThreadLocal /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T: ?Sized + Send> CachedThreadLocal<T> {$/;" i
|
||||
CachedThreadLocal /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T: Send + Default> CachedThreadLocal<T> {$/;" i
|
||||
CachedThreadLocal /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^pub struct CachedThreadLocal<T: ?Sized + Send> {$/;" s
|
||||
CheckOwned /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/tests.rs /^ struct CheckOwned;$/;" s
|
||||
Clone for TableEntry /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T: ?Sized + Send> Clone for TableEntry<T> {$/;" i
|
||||
Default for CachedThreadLocal /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T: ?Sized + Send> Default for CachedThreadLocal<T> {$/;" i
|
||||
Default for ThreadLocal /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T: ?Sized + Send> Default for ThreadLocal<T> {$/;" i
|
||||
Discard /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^pub struct Discard;$/;" s
|
||||
Drain /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^pub trait Drain {$/;" t
|
||||
Drain for Arc /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^impl<D: Drain+?Sized> Drain for Arc<D> {$/;" i
|
||||
Drain for Async /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^impl Drain for Async {$/;" i
|
||||
Drain for Box /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^impl<D: Drain+?Sized> Drain for Box<D> {$/;" i
|
||||
Drain for CheckOwned /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/tests.rs /^ impl Drain for CheckOwned {$/;" i
|
||||
Drain for Discard /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^impl Drain for Discard {$/;" i
|
||||
Drain for Duplicate /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^impl<D1 : Drain, D2 : Drain> Drain for Duplicate<D1, D2> {$/;" i
|
||||
Drain for Filter /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^impl<D: Drain> Drain for Filter<D> {$/;" i
|
||||
Drain for Fuse /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^impl<D: Drain> Drain for Fuse<D> where D::Error : fmt::Display {$/;" i
|
||||
Drain for IgnoreErr /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^impl<D: Drain> Drain for IgnoreErr<D> {$/;" i
|
||||
Drain for LevelFilter /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^impl<D: Drain> Drain for LevelFilter<D> {$/;" i
|
||||
Drain for Logger /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_logger.rs /^impl Drain for Logger {$/;" i
|
||||
Drain for MapError /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^impl<D: Drain, E> Drain for MapError<D, E> {$/;" i
|
||||
Drain for Streamer /home/dpc/lab/rust/slog/slog-stream/lib.rs /^impl<W: 'static + io::Write + Send, F: Format + Send> Drain for Streamer<W, F> {$/;" i
|
||||
DrainExt /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^pub trait DrainExt: Sized + Drain {$/;" t
|
||||
DrainExt for D /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^impl<D : Drain> DrainExt for D {}$/;" i
|
||||
Drop for Async /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^impl Drop for Async {$/;" i
|
||||
Drop for PushFnSerializer /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl<'a> Drop for PushFnSerializer<'a> {$/;" i
|
||||
Drop for ThreadLocal /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T: ?Sized + Send> Drop for ThreadLocal<T> {$/;" i
|
||||
Duplicate /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^impl<D1: Drain, D2: Drain> Duplicate<D1, D2> {$/;" i
|
||||
Duplicate /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^pub struct Duplicate<D1: Drain, D2: Drain> {$/;" s
|
||||
DuplicateError /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^pub enum DuplicateError<E1, E2> {$/;" g
|
||||
Err /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^ type Err = ();$/;" T
|
||||
Error /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ type Error = io::Error;$/;" T
|
||||
Error /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ type Error = D::Error;$/;" T
|
||||
Error /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ type Error = DuplicateError<D1::Error, D2::Error>;$/;" T
|
||||
Error /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ type Error = E;$/;" T
|
||||
Error /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ type Error = Never;$/;" T
|
||||
Error /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ type Error;$/;" T
|
||||
Error /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_logger.rs /^ type Error = Never;$/;" T
|
||||
Error /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^pub enum Error {$/;" g
|
||||
Error /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/tests.rs /^ type Error = Never;$/;" T
|
||||
Error /home/dpc/lab/rust/slog/slog-stream/lib.rs /^ type Error = io::Error;$/;" T
|
||||
ExactSizeIterator for IntoIter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T: ?Sized + Send> ExactSizeIterator for IntoIter<T> {}$/;" i
|
||||
ExactSizeIterator for IterMut /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<'a, T: ?Sized + Send + 'a> ExactSizeIterator for IterMut<'a, T> {}$/;" i
|
||||
Filter /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^impl<D: Drain> Filter<D> {$/;" i
|
||||
Filter /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^pub struct Filter<D: Drain> {$/;" s
|
||||
FilterLevel /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^impl FilterLevel {$/;" i
|
||||
FilterLevel /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^pub enum FilterLevel {$/;" g
|
||||
FnValue /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^pub struct FnValue<V: 'static + Value, F>(pub F)$/;" s
|
||||
Format /home/dpc/lab/rust/slog/slog-stream/format.rs /^pub trait Format: Send + Sync + Sized {$/;" t
|
||||
From for Error /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl From<core::fmt::Error> for Error {$/;" i
|
||||
From for Error /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl From<std::io::Error> for Error {$/;" i
|
||||
From for std /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl From<Error> for std::io::Error {$/;" i
|
||||
FromStr for FilterLevel /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^impl FromStr for FilterLevel {$/;" i
|
||||
Fuse /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^impl<D: Drain> Fuse<D> {$/;" i
|
||||
Fuse /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^pub struct Fuse<D: Drain> {$/;" s
|
||||
IgnoreErr /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^impl<D: Drain> IgnoreErr<D> {$/;" i
|
||||
IgnoreErr /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^pub struct IgnoreErr<D: Drain> {$/;" s
|
||||
IntoIter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ type IntoIter = CachedIntoIter<T>;$/;" T
|
||||
IntoIter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ type IntoIter = CachedIterMut<'a, T>;$/;" T
|
||||
IntoIter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ type IntoIter = IntoIter<T>;$/;" T
|
||||
IntoIter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ type IntoIter = IterMut<'a, T>;$/;" T
|
||||
IntoIter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^pub struct IntoIter<T: ?Sized + Send> {$/;" s
|
||||
IntoIterator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<'a, T: ?Sized + Send + 'a> IntoIterator for &'a mut CachedThreadLocal<T> {$/;" i
|
||||
IntoIterator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<'a, T: ?Sized + Send + 'a> IntoIterator for &'a mut ThreadLocal<T> {$/;" i
|
||||
IntoIterator for CachedThreadLocal /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T: ?Sized + Send> IntoIterator for CachedThreadLocal<T> {$/;" i
|
||||
IntoIterator for ThreadLocal /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T: ?Sized + Send> IntoIterator for ThreadLocal<T> {$/;" i
|
||||
Item /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^ type Item = &'a KV;$/;" T
|
||||
Item /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ type Item = &'a mut Box<T>;$/;" T
|
||||
Item /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ type Item = Box<T>;$/;" T
|
||||
IterMut /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^pub struct IterMut<'a, T: ?Sized + Send + 'a> {$/;" s
|
||||
Iterator for IntoIter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T: ?Sized + Send> Iterator for IntoIter<T> {$/;" i
|
||||
Iterator for IterMut /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<'a, T: ?Sized + Send + 'a> Iterator for IterMut<'a, T> {$/;" i
|
||||
Iterator for OwnedKVGroupIterator /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^impl<'a> Iterator for OwnedKVGroupIterator<'a> {$/;" i
|
||||
Iterator for OwnedKVIterator /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^impl<'a> Iterator for OwnedKVIterator<'a> {$/;" i
|
||||
KV /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl KV for () {$/;" i
|
||||
KV /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl<T: KV, R: KV> KV for (T, R) {$/;" i
|
||||
KV /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^pub trait KV {$/;" t
|
||||
KV for SingleKV /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl<K, V> KV for SingleKV<K, V>$/;" i
|
||||
Key /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl<'a> Key for &'a str {$/;" i
|
||||
Key /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^pub trait Key {$/;" t
|
||||
Key for String /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl Key for String {$/;" i
|
||||
Key for str /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl Key for str {$/;" i
|
||||
LOG_LEVEL_NAMES /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^pub static LOG_LEVEL_NAMES: [&'static str; 7] = ["OFF", "CRITICAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"];$/;" c
|
||||
LOG_LEVEL_SHORT_NAMES /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^pub static LOG_LEVEL_SHORT_NAMES: [&'static str; 7] = ["OFF", "CRIT", "ERRO", "WARN", "INFO", "DEBG", "TRCE"];$/;" c
|
||||
Level /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^impl Level {$/;" i
|
||||
Level /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^pub enum Level {$/;" g
|
||||
LevelFilter /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^impl<D: Drain> LevelFilter<D> {$/;" i
|
||||
LevelFilter /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^pub struct LevelFilter<D: Drain> {$/;" s
|
||||
Logger /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_logger.rs /^impl Logger {$/;" i
|
||||
Logger /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_logger.rs /^pub struct Logger {$/;" s
|
||||
MapError /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^impl<D: Drain, E> MapError<D, E> {$/;" i
|
||||
MapError /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^pub struct MapError<D: Drain, E> {$/;" s
|
||||
Never /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/lib.rs /^pub type Never = ();$/;" T
|
||||
OwnedKVGroup /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^pub struct OwnedKVGroup($/;" s
|
||||
OwnedKVGroupIterator /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^impl<'a> OwnedKVGroupIterator<'a> {$/;" i
|
||||
OwnedKVGroupIterator /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^pub struct OwnedKVGroupIterator<'a> {$/;" s
|
||||
OwnedKVIterator /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^impl<'a> OwnedKVIterator<'a> {$/;" i
|
||||
OwnedKVIterator /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^pub struct OwnedKVIterator<'a> {$/;" s
|
||||
OwnedKVList /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^impl OwnedKVList {$/;" i
|
||||
OwnedKVList /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^pub struct OwnedKVList {$/;" s
|
||||
OwnedKVListNode /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^struct OwnedKVListNode {$/;" s
|
||||
PushFnSerializer /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl<'a> PushFnSerializer<'a> {$/;" i
|
||||
PushFnSerializer /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^pub struct PushFnSerializer<'a> {$/;" s
|
||||
PushFnValue /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^pub struct PushFnValue<F>(pub F)$/;" s
|
||||
RS /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^ static RS : $crate::RecordStatic<'static> = $crate::RecordStatic {$/;" c
|
||||
RawIter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T: ?Sized + Send> RawIter<T> {$/;" i
|
||||
RawIter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^struct RawIter<T: ?Sized + Send> {$/;" s
|
||||
Record /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_record.rs /^impl<'a> Record<'a> {$/;" i
|
||||
Record /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_record.rs /^pub struct Record<'a> {$/;" s
|
||||
RecordStatic /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_record.rs /^pub struct RecordStatic<'a> {$/;" s
|
||||
RecordValues /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^type RecordValues = Vec<Box<slog::KV+Send>>;$/;" T
|
||||
Result /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^pub type Result<T=()> = result::Result<T, Error>;$/;" T
|
||||
STATIC_TERMINATOR_UNIT /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^static STATIC_TERMINATOR_UNIT : () = ();$/;" c
|
||||
Serializer /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^pub trait Serializer {$/;" t
|
||||
Serializer for AsFmtSerializer /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl<F> Serializer for AsFmtSerializer<F>$/;" i
|
||||
Serializer for ToSendSerializer /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^impl Serializer for ToSendSerializer {$/;" i
|
||||
SingleKV /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^pub struct SingleKV<K, V>(pub K, pub V)$/;" s
|
||||
Streamer /home/dpc/lab/rust/slog/slog-stream/lib.rs /^impl<W: io::Write, F: Format> Streamer<W, F> {$/;" i
|
||||
Streamer /home/dpc/lab/rust/slog/slog-stream/lib.rs /^pub struct Streamer<W: io::Write, F: Format> {$/;" s
|
||||
Sync for CachedThreadLocal /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^unsafe impl<T: ?Sized + Send> Sync for CachedThreadLocal<T> {}$/;" i
|
||||
Sync for ThreadLocal /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^unsafe impl<T: ?Sized + Send> Sync for ThreadLocal<T> {}$/;" i
|
||||
TL_BUF /home/dpc/lab/rust/slog/slog-stream/lib.rs /^ static TL_BUF: RefCell<Vec<u8>> = RefCell::new(Vec::with_capacity(128))$/;" c
|
||||
Table /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^struct Table<T: ?Sized + Send> {$/;" s
|
||||
TableEntry /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^struct TableEntry<T: ?Sized + Send> {$/;" s
|
||||
ThreadLocal /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T: ?Sized + Send> ThreadLocal<T> {$/;" i
|
||||
ThreadLocal /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T: Send + Default> ThreadLocal<T> {$/;" i
|
||||
ThreadLocal /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^pub struct ThreadLocal<T: ?Sized + Send> {$/;" s
|
||||
ToSendSerializer /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^impl ToSendSerializer {$/;" i
|
||||
ToSendSerializer /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^struct ToSendSerializer {$/;" s
|
||||
UncheckedOptionExt /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^trait UncheckedOptionExt<T> {$/;" t
|
||||
UncheckedOptionExt for Option /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T> UncheckedOptionExt<T> for Option<T> {$/;" i
|
||||
UncheckedOptionExt for Result /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T, E> UncheckedOptionExt<T> for Result<T, E> {$/;" i
|
||||
Value /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ impl Value for $t {$/;" i
|
||||
Value /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl Value for () {$/;" i
|
||||
Value /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl<'a> Value for &'a str {$/;" i
|
||||
Value /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^pub trait Value {$/;" t
|
||||
Value for Arc /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl<T> Value for Arc<T>$/;" i
|
||||
Value for Box /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl Value for Box<Value + Send + 'static> {$/;" i
|
||||
Value for F /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl<V: 'static + Value, F> Value for F$/;" i
|
||||
Value for FnValue /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl<V: 'static + Value, F> Value for FnValue<V, F>$/;" i
|
||||
Value for Option /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl<T: Value> Value for Option<T> {$/;" i
|
||||
Value for PushFnValue /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl<F> Value for PushFnValue<F>$/;" i
|
||||
Value for Rc /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl<T> Value for Rc<T>$/;" i
|
||||
Value for String /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl Value for String {$/;" i
|
||||
Value for core /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl<T> Value for core::num::Wrapping<T>$/;" i
|
||||
Value for fmt /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl<'a> Value for fmt::Arguments<'a> {$/;" i
|
||||
Value for str /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl Value for str {$/;" i
|
||||
Void /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ enum Void {}$/;" g
|
||||
__slog_static_max_level /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^pub fn __slog_static_max_level() -> FilterLevel {$/;" f
|
||||
append /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^ fn append(&self, other: &OwnedKVList) -> OwnedKVList {$/;" f
|
||||
as_short_str /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^ pub fn as_short_str(&self) -> &'static str {$/;" f
|
||||
as_str /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^ pub fn as_str(&self) -> &'static str {$/;" f
|
||||
as_str /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn as_str(&self) -> &str {$/;" f
|
||||
as_str /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn as_str(&self) -> &str;$/;" f
|
||||
as_usize /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^ pub fn as_usize(&self) -> usize {$/;" f
|
||||
async_stream /home/dpc/lab/rust/slog/slog-stream/lib.rs /^pub fn async_stream<W: io::Write + Send + 'static, F: Format + Send + 'static>(io: W,$/;" f
|
||||
cause /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn cause(&self) -> Option<&std::error::Error> {$/;" f
|
||||
clear /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ pub fn clear(&mut self) {$/;" f
|
||||
clone /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn clone(&self) -> TableEntry<T> {$/;" f
|
||||
column /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_record.rs /^ pub fn column(&self) -> u32 {$/;" f
|
||||
core::fmt::Display for Error /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl core::fmt::Display for Error {$/;" i
|
||||
crit /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^macro_rules! crit($/;" d
|
||||
debug /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^macro_rules! debug($/;" d
|
||||
default /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn default() -> CachedThreadLocal<T> {$/;" f
|
||||
default /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn default() -> ThreadLocal<T> {$/;" f
|
||||
description /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn description(&self) -> &str {$/;" f
|
||||
different_thread /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn different_thread() {$/;" f
|
||||
different_thread_cached /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn different_thread_cached() {$/;" f
|
||||
drop /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn drop(&mut self) {$/;" f
|
||||
drop /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn drop(&mut self) {$/;" f
|
||||
drop /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn drop(&mut self) {$/;" f
|
||||
duplicate /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^pub fn duplicate<D1: Drain, D2: Drain>(d1: D1, d2: D2) -> Duplicate<D1, D2> {$/;" f
|
||||
emit_arguments /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_arguments(&mut self, key: &str, val: &fmt::Arguments) -> slog::Result {$/;" f
|
||||
emit_arguments /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn emit_arguments(&mut self, key: &str, val: &fmt::Arguments) -> Result {$/;" f
|
||||
emit_arguments /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn emit_arguments(&mut self, key: &str, val: &fmt::Arguments) -> Result;$/;" f
|
||||
emit_bool /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_bool(&mut self, key: &str, val: bool) -> slog::Result {$/;" f
|
||||
emit_char /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_char(&mut self, key: &str, val: char) -> slog::Result {$/;" f
|
||||
emit_f32 /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_f32(&mut self, key: &str, val: f32) -> slog::Result {$/;" f
|
||||
emit_f64 /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_f64(&mut self, key: &str, val: f64) -> slog::Result {$/;" f
|
||||
emit_i16 /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_i16(&mut self, key: &str, val: i16) -> slog::Result {$/;" f
|
||||
emit_i32 /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_i32(&mut self, key: &str, val: i32) -> slog::Result {$/;" f
|
||||
emit_i64 /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_i64(&mut self, key: &str, val: i64) -> slog::Result {$/;" f
|
||||
emit_i8 /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_i8(&mut self, key: &str, val: i8) -> slog::Result {$/;" f
|
||||
emit_isize /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_isize(&mut self, key: &str, val: isize) -> slog::Result {$/;" f
|
||||
emit_none /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_none(&mut self, key: &str) -> slog::Result {$/;" f
|
||||
emit_none /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn emit_none(&mut self, key: &str) -> Result {$/;" f
|
||||
emit_str /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_str(&mut self, key: &str, val: &str) -> slog::Result {$/;" f
|
||||
emit_u16 /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_u16(&mut self, key: &str, val: u16) -> slog::Result {$/;" f
|
||||
emit_u32 /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_u32(&mut self, key: &str, val: u32) -> slog::Result {$/;" f
|
||||
emit_u64 /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_u64(&mut self, key: &str, val: u64) -> slog::Result {$/;" f
|
||||
emit_u8 /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_u8(&mut self, key: &str, val: u8) -> slog::Result {$/;" f
|
||||
emit_unit /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_unit(&mut self, key: &str) -> slog::Result {$/;" f
|
||||
emit_unit /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn emit_unit(&mut self, key: &str) -> Result {$/;" f
|
||||
emit_usize /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn emit_usize(&mut self, key: &str, val: usize) -> slog::Result {$/;" f
|
||||
error /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^macro_rules! error($/;" d
|
||||
file /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_record.rs /^ pub fn file(&self) -> &'static str {$/;" f
|
||||
filter /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^pub fn filter<D: Drain, F: 'static + Send + Sync + Fn(&Record) -> bool>($/;" f
|
||||
filterlevel_sanity /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^fn filterlevel_sanity() {$/;" f
|
||||
finish /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn finish(self) -> RecordValues {$/;" f
|
||||
fmt /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {$/;" f
|
||||
fmt /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {$/;" f
|
||||
fmt /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {$/;" f
|
||||
fmt /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_logger.rs /^ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {$/;" f
|
||||
fmt /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn fmt(&self, fmt: &mut core::fmt::Formatter) -> std::fmt::Result {$/;" f
|
||||
fmt /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {$/;" f
|
||||
fmt::Debug for CachedThreadLocal /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T: ?Sized + Send + fmt::Debug> fmt::Debug for CachedThreadLocal<T> {$/;" i
|
||||
fmt::Debug for Logger /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_logger.rs /^impl fmt::Debug for Logger {$/;" i
|
||||
fmt::Debug for OwnedKVList /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^impl fmt::Debug for OwnedKVList {$/;" i
|
||||
fmt::Debug for ThreadLocal /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^impl<T: ?Sized + Send + fmt::Debug> fmt::Debug for ThreadLocal<T> {$/;" i
|
||||
fmt::Display for DuplicateError /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^impl<E1 : fmt::Display, E2 : fmt::Display> fmt::Display for DuplicateError<E1, E2> {$/;" i
|
||||
fmt::Display for Level /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^impl fmt::Display for Level {$/;" i
|
||||
foo /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn foo<T: Sync>() {}$/;" f
|
||||
format /home/dpc/lab/rust/slog/slog-stream/format.rs /^ fn format(&self,$/;" f
|
||||
from /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn from(_: core::fmt::Error) -> Error {$/;" f
|
||||
from /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn from(e: Error) -> std::io::Error {$/;" f
|
||||
from /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn from(err: std::io::Error) -> Error {$/;" f
|
||||
from_raw /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ unsafe fn from_raw(raw: *mut T) -> Self {$/;" f
|
||||
from_raw /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ unsafe fn from_raw(raw: *mut T) -> Self;$/;" f
|
||||
from_str /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^ fn from_str(level: &str) -> core::result::Result<FilterLevel, ()> {$/;" f
|
||||
from_usize /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^ pub fn from_usize(u: usize) -> Option<FilterLevel> {$/;" f
|
||||
from_usize /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^ pub fn from_usize(u: usize) -> Option<Level> {$/;" f
|
||||
function /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_record.rs /^ pub fn function(&self) -> &'static str {$/;" f
|
||||
fuse /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ fn fuse(self) -> Fuse<Self> where <Self as Drain>::Error : fmt::Display {$/;" f
|
||||
get /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ pub fn get(&self) -> Option<&T> {$/;" f
|
||||
get_default /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ pub fn get_default(&self) -> &T {$/;" f
|
||||
get_fast /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn get_fast(&self, id: usize) -> Option<&T> {$/;" f
|
||||
get_or /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ pub fn get_or<F>(&self, create: F) -> &T$/;" f
|
||||
get_or_try /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ pub fn get_or_try<F, E>(&self, create: F) -> Result<&T, E>$/;" f
|
||||
get_or_try_slow /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn get_or_try_slow<F, E>(&self, id: usize, owner: usize, create: F) -> Result<&T, E>$/;" f
|
||||
get_sender /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn get_sender(&self) -> &mpsc::Sender<AsyncMsg> {$/;" f
|
||||
get_slow /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn get_slow(&self, id: usize, table_top: &Table<T>) -> Option<&T> {$/;" f
|
||||
hash /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^fn hash(id: usize, bits: usize) -> usize {$/;" f
|
||||
ignore_err /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ fn ignore_err(self) -> IgnoreErr<Self> {$/;" f
|
||||
impl_default_as_fmt /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^macro_rules! impl_default_as_fmt{$/;" d
|
||||
impl_value_for /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^macro_rules! impl_value_for{$/;" d
|
||||
info /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^macro_rules! info($/;" d
|
||||
insert /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn insert(&self, id: usize, data: Box<T>, new: bool) -> &T {$/;" f
|
||||
into_iter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn into_iter(self) -> CachedIntoIter<T> {$/;" f
|
||||
into_iter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn into_iter(self) -> CachedIterMut<'a, T> {$/;" f
|
||||
into_iter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn into_iter(self) -> IntoIter<T> {$/;" f
|
||||
into_iter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn into_iter(self) -> IterMut<'a, T> {$/;" f
|
||||
into_raw /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn into_raw(b: Self) -> *mut T;$/;" f
|
||||
into_raw /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn into_raw(mut b: Self) -> *mut T {$/;" f
|
||||
is_at_least /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^ pub fn is_at_least(&self, level : Self) -> bool {$/;" f
|
||||
is_sync /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn is_sync() {$/;" f
|
||||
iter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn iter() {$/;" f
|
||||
iter_cached /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn iter_cached() {$/;" f
|
||||
iter_groups /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^ pub fn iter_groups(&self) -> OwnedKVGroupIterator {$/;" f
|
||||
iter_mut /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ pub fn iter_mut(&mut self) -> CachedIterMut<T> {$/;" f
|
||||
iter_mut /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ pub fn iter_mut(&mut self) -> IterMut<T> {$/;" f
|
||||
iter_single /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^ pub fn iter_single(&self) -> OwnedKVIterator {$/;" f
|
||||
level /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_record.rs /^ pub fn level(&self) -> Level {$/;" f
|
||||
level_at_least /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^fn level_at_least() {$/;" f
|
||||
level_filter /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^pub fn level_filter<D: Drain>(level: Level, d: D) -> LevelFilter<D> {$/;" f
|
||||
level_from_str /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^fn level_from_str() {$/;" f
|
||||
line /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_record.rs /^ pub fn line(&self) -> u32 {$/;" f
|
||||
log /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn log(&self, record: &Record, logger_values: &OwnedKVList) -> io::Result<()> {$/;" f
|
||||
log /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ fn log(&self, _: &Record, _: &OwnedKVList) -> result::Result<(), Never> {$/;" f
|
||||
log /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ fn log(&self, info: &Record, o: &OwnedKVList) -> result::Result<(), D::Error> {$/;" f
|
||||
log /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ fn log(&self, record: &Record, values : &OwnedKVList) -> result::Result<(), Self::Error>;$/;" f
|
||||
log /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ fn log(&self,$/;" f
|
||||
log /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_logger.rs /^ fn log(&self, record: &Record, values : &OwnedKVList) -> result::Result<(), Self::Error> {$/;" f
|
||||
log /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_logger.rs /^ pub fn log(&self, record: &Record) {$/;" f
|
||||
log /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^macro_rules! log($/;" d
|
||||
log /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/tests.rs /^ fn log(&self,$/;" f
|
||||
log /home/dpc/lab/rust/slog/slog-stream/lib.rs /^ fn log(&self, info: &Record, logger_values: &OwnedKVList) -> io::Result<()> {$/;" f
|
||||
logger_fmt_debug_sanity /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/tests.rs /^ fn logger_fmt_debug_sanity() {$/;" f
|
||||
lookup /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn lookup(id: usize, table: &Table<T>) -> Option<&UnsafeCell<Option<Box<T>>>> {$/;" f
|
||||
make_create /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn make_create() -> Arc<Fn() -> Box<usize> + Send + Sync> {$/;" f
|
||||
map_err /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ fn map_err<F, E>(self, f : F) -> MapError<Self, E> where F : 'static + Sync + Send + Fn(<Self as Drain>::Error) -> E {$/;" f
|
||||
max /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^ pub fn max() -> Self {$/;" f
|
||||
min /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_level.rs /^ pub fn min() -> Self {$/;" f
|
||||
module /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_record.rs /^ pub fn module(&self) -> &'static str {$/;" f
|
||||
msg /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_record.rs /^ pub fn msg(&self) -> fmt::Arguments {$/;" f
|
||||
multichain /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/tests.rs /^ fn multichain() {$/;" f
|
||||
new /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn new() -> Self {$/;" f
|
||||
new /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ pub fn new<D: slog::Drain<Error=slog::Never> + Send + 'static>(drain: D) -> Self {$/;" f
|
||||
new /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ pub fn new(drain1: D1, drain2: D2) -> Self {$/;" f
|
||||
new /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ pub fn new(drain: D) -> Self {$/;" f
|
||||
new /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ pub fn new(drain: D, level: Level) -> Self {$/;" f
|
||||
new /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ pub fn new<F: 'static + Sync + Send + Fn(&Record) -> bool>(drain: D, cond: F) -> Self {$/;" f
|
||||
new /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_drain.rs /^ pub fn new<F: 'static + Sync + Send + Fn(<D as Drain>::Error) -> E>(drain: D, map_fn: F) -> Self {$/;" f
|
||||
new /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^ fn new(list: &'a OwnedKVList) -> Self {$/;" f
|
||||
new /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^ fn new(values: OwnedKVGroup, parent: &OwnedKVList) -> Self {$/;" f
|
||||
new /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_logger.rs /^ pub fn new(&self, values: OwnedKVGroup) -> Logger {$/;" f
|
||||
new /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_record.rs /^ pub fn new($/;" f
|
||||
new /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ pub fn new() -> CachedThreadLocal<T> {$/;" f
|
||||
new /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ pub fn new() -> ThreadLocal<T> {$/;" f
|
||||
new /home/dpc/lab/rust/slog/slog-stream/lib.rs /^ pub fn new(io: W, format: F) -> Self {$/;" f
|
||||
next /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^ fn next(&mut self) -> Option<Self::Item> {$/;" f
|
||||
next /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn next(&mut self) -> Option<&'a mut Box<T>> {$/;" f
|
||||
next /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn next(&mut self) -> Option<*mut Option<Box<T>>> {$/;" f
|
||||
next /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn next(&mut self) -> Option<Box<T>> {$/;" f
|
||||
no_imports /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/tests.rs /^mod no_imports {$/;" m
|
||||
o /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^macro_rules! o($/;" d
|
||||
root /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_kv.rs /^ fn root(values: OwnedKVGroup) -> Self {$/;" f
|
||||
root /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_logger.rs /^ pub fn root<D>(d: D, values: OwnedKVGroup) -> Logger$/;" f
|
||||
same_thread /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn same_thread() {$/;" f
|
||||
same_thread_cached /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn same_thread_cached() {$/;" f
|
||||
send /home/dpc/.cargo/git/checkouts/extra-4841682ba715deeb/35f528f/lib.rs /^ fn send(&self, r: AsyncRecord) -> io::Result<()> {$/;" f
|
||||
serialize /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn serialize(&self, _record : &Record, key : &str, serializer : &mut Serializer)$/;" f
|
||||
serialize /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn serialize(&self, record: &Record, key: &str, serializer: &mut Serializer)$/;" f
|
||||
serialize /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn serialize(&self,$/;" f
|
||||
serialize /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ pub fn serialize<'b, S: 'b + Value>(mut self, s: S) -> Result {$/;" f
|
||||
size_hint /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ fn size_hint(&self) -> (usize, Option<usize>) {$/;" f
|
||||
slog_crit /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^macro_rules! slog_crit($/;" d
|
||||
slog_debug /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^macro_rules! slog_debug($/;" d
|
||||
slog_error /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^macro_rules! slog_error($/;" d
|
||||
slog_info /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^macro_rules! slog_info($/;" d
|
||||
slog_log /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^macro_rules! slog_log($/;" d
|
||||
slog_o /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^macro_rules! slog_o($/;" d
|
||||
slog_trace /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^macro_rules! slog_trace($/;" d
|
||||
slog_warn /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^macro_rules! slog_warn($/;" d
|
||||
split_first /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn split_first(&self) -> Option<(&KV, &KV)> {$/;" f
|
||||
split_first /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^ fn split_first(&self) -> Option<(&KV, &KV)>;$/;" f
|
||||
std::error::Error for Error /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_ser.rs /^impl std::error::Error for Error {$/;" i
|
||||
std_only /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/tests.rs /^mod std_only {$/;" m
|
||||
stream /home/dpc/lab/rust/slog/slog-stream/lib.rs /^pub fn stream<W: io::Write + Send, F: Format>(io: W, format: F) -> Streamer<W, F> {$/;" f
|
||||
target /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_record.rs /^ pub fn target(&self) -> &str {$/;" f
|
||||
test_o_macro_expansion /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/tests.rs /^ fn test_o_macro_expansion() {$/;" f
|
||||
test_slog_o_macro_expansion /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/tests.rs /^ fn test_slog_o_macro_expansion() {$/;" f
|
||||
tests /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/lib.rs /^mod tests;$/;" m
|
||||
tests /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^mod tests {$/;" m
|
||||
trace /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^macro_rules! trace($/;" d
|
||||
unchecked_unwrap /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ unsafe fn unchecked_unwrap(self) -> T {$/;" f
|
||||
unchecked_unwrap /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^ unsafe fn unchecked_unwrap(self) -> T;$/;" f
|
||||
unreachable /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/thread_local-0.2.7/src/lib.rs /^unsafe fn unreachable() -> ! {$/;" f
|
||||
values /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_record.rs /^ pub fn values(&self) -> &'a [&KV] {$/;" f
|
||||
warn /home/dpc/.cargo/git/checkouts/slog-1186f70b488e4d02/00b4390/src/_macros.rs /^macro_rules! warn($/;" d
|
|
@ -1 +0,0 @@
|
|||
{"files":{".travis.yml":"88727d3c65d8328457560104264358b567a339dcebc3f6c4df3ba308f1944acc","CHANGELOG.md":"44eba7dd11980076bfc44fb83fc3b23aee1b82812530e64aac88ccb2b1d9325d","Cargo.toml":"973e07ab059f6448873cea70433c7212b39aff0a53062c1da401a2ab9bb60799","LICENSE-MPL2":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","Makefile":"500a3af82638116a8d782b74091185fa7440b38cce99dd0b246e9965807d48b1","README.md":"134ae4eb1e4799f9aeab997b3e9b5dc1fdc5170b897f9722844d2245c1f6a4c9","lib.rs":"7065ed5a7c9ec2252f1b5f58c7f339502c28f54edc6b444c2f3f0e168714cc19"},"package":"cb53c0bae0745898fd5a7b75b1c389507333470ac4c645ae431890c0f828b6ca"}
|
|
@ -1,26 +0,0 @@
|
|||
language: rust
|
||||
rust:
|
||||
- stable
|
||||
- 1.12.0
|
||||
- beta
|
||||
- nightly
|
||||
|
||||
script:
|
||||
- make all
|
||||
- make travistest
|
||||
- if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then make bench ; fi
|
||||
|
||||
env:
|
||||
global:
|
||||
- RUST_BACKTRACE=1
|
||||
matrix:
|
||||
-
|
||||
- RELEASE=true
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/6d8e17dd2fa83b143168
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
on_failure: change # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
|
@ -1,66 +0,0 @@
|
|||
# Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 1.5.0 - 2017-02-05
|
||||
### Change
|
||||
|
||||
* Reverse the order of record values in full mode to match slog 1.5
|
||||
definition
|
||||
|
||||
## 1.4.0 - 2017-01-29
|
||||
### Changed
|
||||
|
||||
* Fix a bug in `new_plain` that would make it still use colors.
|
||||
* No comma will be printed after an empty "msg" field
|
||||
* Changed order of full format values
|
||||
|
||||
## 1.3.5 - 2016-01-13
|
||||
### Fixed
|
||||
|
||||
* [1.3.4 with `?` operator breaks semver](https://github.com/slog-rs/term/issues/6) - fix allows builds on stable Rust back to 1.11
|
||||
|
||||
## 1.3.4 - 2016-12-27
|
||||
### Fixed
|
||||
|
||||
* [Fix compact formatting grouping messages incorrectly](https://github.com/slog-rs/slog/issues/90)
|
||||
|
||||
## 1.3.3 - 2016-10-31
|
||||
### Changed
|
||||
|
||||
* Added `Send+Sync` to `Drain` returned on `build`
|
||||
|
||||
## 1.3.2 - 2016-10-22
|
||||
### Changed
|
||||
|
||||
* Fix compact format, repeating some values unnecessarily.
|
||||
|
||||
## 1.3.1 - 2016-10-22
|
||||
### Changed
|
||||
|
||||
* Make `Format` public so it can be reused
|
||||
|
||||
## 1.3.0 - 2016-10-21
|
||||
### Changed
|
||||
|
||||
* **BREAKING**: Switched `AsyncStramer` to `slog_extra::Async`
|
||||
|
||||
## 1.2.0 - 2016-10-17
|
||||
### Changed
|
||||
|
||||
* **BREAKING**: Rewrite handling of owned values.
|
||||
|
||||
## 1.1.0 - 2016-09-28
|
||||
### Added
|
||||
|
||||
* Custom timestamp function support
|
||||
|
||||
### Changed
|
||||
|
||||
* Logging level color uses only first 8 ANSI terminal colors for better compatibility
|
||||
|
||||
## 1.0.0 - 2016-09-21
|
||||
|
||||
First stable release.
|
|
@ -1,21 +0,0 @@
|
|||
[package]
|
||||
name = "slog-term"
|
||||
version = "1.5.0"
|
||||
authors = ["Dawid Ciężarkiewicz <dpc@dpc.pw>"]
|
||||
description = "Unix terminal drain and formatter for slog-rs"
|
||||
keywords = ["slog", "logging", "log", "term"]
|
||||
license = "MPL-2.0"
|
||||
documentation = "https://docs.rs/slog-term"
|
||||
homepage = "https://github.com/slog-rs/slog"
|
||||
repository = "https://github.com/slog-rs/term"
|
||||
readme = "README.md"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
slog = "1.5.0"
|
||||
slog-stream = "1.2"
|
||||
isatty = "0.1"
|
||||
chrono = "0.2"
|
||||
thread_local = "0.3"
|
|
@ -1,373 +0,0 @@
|
|||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
|
@ -1,68 +0,0 @@
|
|||
PKG_NAME=$(shell grep name Cargo.toml | head -n 1 | awk -F \" '{print $$2}')
|
||||
DOCS_DEFAULT_MODULE=$(subst -,_,$(PKG_NAME))
|
||||
ifeq (, $(shell which cargo-check 2> /dev/null))
|
||||
DEFAULT_TARGET=build
|
||||
else
|
||||
DEFAULT_TARGET=build
|
||||
endif
|
||||
|
||||
default: $(DEFAULT_TARGET)
|
||||
|
||||
ALL_TARGETS += build $(EXAMPLES) test doc
|
||||
ifneq ($(RELEASE),)
|
||||
$(info RELEASE BUILD: $(PKG_NAME))
|
||||
CARGO_FLAGS += --release
|
||||
else
|
||||
$(info DEBUG BUILD: $(PKG_NAME); use `RELEASE=true make [args]` for release build)
|
||||
endif
|
||||
|
||||
EXAMPLES = $(shell cd examples 2>/dev/null && ls *.rs 2>/dev/null | sed -e 's/.rs$$//g' )
|
||||
|
||||
all: $(ALL_TARGETS)
|
||||
|
||||
.PHONY: run test build doc clean clippy
|
||||
run test build clean:
|
||||
cargo $@ $(CARGO_FLAGS)
|
||||
|
||||
check:
|
||||
$(info Running check; use `make build` to actually build)
|
||||
cargo $@ $(CARGO_FLAGS)
|
||||
|
||||
clippy:
|
||||
cargo build --features clippy
|
||||
|
||||
.PHONY: bench
|
||||
bench:
|
||||
cargo $@ $(filter-out --release,$(CARGO_FLAGS))
|
||||
|
||||
.PHONY: travistest
|
||||
travistest: test
|
||||
|
||||
.PHONY: longtest
|
||||
longtest:
|
||||
@echo "Running longtest. Press Ctrl+C to stop at any time"
|
||||
@sleep 2
|
||||
@i=0; while i=$$((i + 1)) && echo "Iteration $$i" && make test ; do :; done
|
||||
|
||||
.PHONY: $(EXAMPLES)
|
||||
$(EXAMPLES):
|
||||
cargo build --example $@ $(CARGO_FLAGS)
|
||||
|
||||
.PHONY: doc
|
||||
doc: FORCE
|
||||
cargo doc
|
||||
|
||||
.PHONY: publishdoc
|
||||
publishdoc:
|
||||
rm -rf target/doc
|
||||
make doc
|
||||
echo '<meta http-equiv="refresh" content="0;url='${DOCS_DEFAULT_MODULE}'/index.html">' > target/doc/index.html
|
||||
ghp-import -n target/doc
|
||||
git push -f origin gh-pages
|
||||
|
||||
.PHONY: docview
|
||||
docview: doc
|
||||
xdg-open target/doc/$(PKG_NAME)/index.html
|
||||
|
||||
.PHONY: FORCE
|
||||
FORCE:
|
|
@ -1,23 +0,0 @@
|
|||
<p align="center">
|
||||
|
||||
<a href="https://github.com/slog-rs/slog">
|
||||
<img src="https://cdn.rawgit.com/slog-rs/misc/master/media/slog.svg" alt="slog-rs logo">
|
||||
</a>
|
||||
<br>
|
||||
|
||||
<a href="https://travis-ci.org/slog-rs/term">
|
||||
<img src="https://img.shields.io/travis/slog-rs/term/master.svg" alt="Travis CI Build Status">
|
||||
</a>
|
||||
|
||||
<a href="https://crates.io/crates/slog-term">
|
||||
<img src="https://img.shields.io/crates/d/slog-term.svg" alt="slog-term on crates.io">
|
||||
</a>
|
||||
|
||||
<a href="https://gitter.im/slog-rs/slog">
|
||||
<img src="https://img.shields.io/gitter/room/slog-rs/slog.svg" alt="slog-rs Gitter Chat">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
# slog-term - Unix terminal drain for [slog-rs]
|
||||
|
||||
[slog-rs]: //github.com/slog-rs/slog
|
|
@ -1,699 +0,0 @@
|
|||
//! Unix terminal formatter and drain for slog-rs
|
||||
//!
|
||||
//! ```
|
||||
//! #[macro_use]
|
||||
//! extern crate slog;
|
||||
//! extern crate slog_term;
|
||||
//!
|
||||
//! use slog::*;
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let root = Logger::root(slog_term::streamer().build().fuse(), o!("build-id" => "8dfljdf"));
|
||||
//! }
|
||||
//! ```
|
||||
#![warn(missing_docs)]
|
||||
|
||||
extern crate slog;
|
||||
extern crate slog_stream;
|
||||
extern crate isatty;
|
||||
extern crate chrono;
|
||||
extern crate thread_local;
|
||||
|
||||
use std::{io, fmt, sync, cell};
|
||||
use std::io::Write;
|
||||
|
||||
use isatty::{stderr_isatty, stdout_isatty};
|
||||
|
||||
use slog::Record;
|
||||
use slog::ser;
|
||||
use slog::{Level, OwnedKeyValueList};
|
||||
use slog_stream::Format as StreamFormat;
|
||||
use slog_stream::{Decorator, RecordDecorator, stream, async_stream};
|
||||
|
||||
thread_local! {
|
||||
static TL_BUF: cell::RefCell<Vec<u8>> = cell::RefCell::new(Vec::with_capacity(128));
|
||||
}
|
||||
|
||||
// Wrapper for `Write` types that counts total bytes written.
|
||||
struct CountingWriter<'a> {
|
||||
wrapped: &'a mut io::Write,
|
||||
count: usize,
|
||||
}
|
||||
|
||||
impl<'a> CountingWriter<'a> {
|
||||
fn new(wrapped: &'a mut io::Write) -> CountingWriter {
|
||||
CountingWriter {
|
||||
wrapped: wrapped,
|
||||
count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn count(&self) -> usize {
|
||||
self.count
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Write for CountingWriter<'a> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.wrapped.write(buf).map(|n| {
|
||||
self.count += n;
|
||||
n
|
||||
})
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.wrapped.flush()
|
||||
}
|
||||
|
||||
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
|
||||
self.wrapped.write_all(buf).map(|_| {
|
||||
self.count += buf.len();
|
||||
()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type WriterFn = Fn(&mut io::Write) -> io::Result<()>;
|
||||
|
||||
// Wrapper for `Write` types that executes a closure before writing anything,
|
||||
// but only if the write isn't empty. A `finish` call executes a closure after
|
||||
// writing, but again, only if something has been written.
|
||||
struct SurroundingWriter<'a> {
|
||||
wrapped: &'a mut io::Write,
|
||||
before: Option<&'a WriterFn>,
|
||||
after: Option<&'a WriterFn>,
|
||||
}
|
||||
|
||||
impl<'a> SurroundingWriter<'a> {
|
||||
fn new(wrapped: &'a mut io::Write,
|
||||
before: &'a WriterFn,
|
||||
after: &'a WriterFn)
|
||||
-> SurroundingWriter<'a> {
|
||||
SurroundingWriter {
|
||||
wrapped: wrapped,
|
||||
before: Some(before),
|
||||
after: Some(after),
|
||||
}
|
||||
}
|
||||
|
||||
fn do_before(&mut self, buf: &[u8]) -> io::Result<()> {
|
||||
if buf.len() > 0 {
|
||||
if let Some(before) = self.before.take() {
|
||||
try!(before(self.wrapped));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn finish(&mut self) -> io::Result<()> {
|
||||
if let Some(after) = self.after.take() {
|
||||
if self.before.is_none() {
|
||||
try!(after(self.wrapped));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for SurroundingWriter<'a> {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.finish();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Write for SurroundingWriter<'a> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
try!(self.do_before(buf));
|
||||
self.wrapped.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.wrapped.flush()
|
||||
}
|
||||
|
||||
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
|
||||
try!(self.do_before(buf));
|
||||
self.wrapped.write_all(buf)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Timestamp function type
|
||||
pub type TimestampFn = Fn(&mut io::Write) -> io::Result<()> + Send + Sync;
|
||||
|
||||
/// Formatting mode
|
||||
pub enum FormatMode {
|
||||
/// Compact logging format
|
||||
Compact,
|
||||
/// Full logging format
|
||||
Full,
|
||||
}
|
||||
|
||||
/// Full formatting with optional color support
|
||||
pub struct Format<D: Decorator> {
|
||||
mode: FormatMode,
|
||||
decorator: D,
|
||||
history: sync::Mutex<Vec<Vec<u8>>>,
|
||||
fn_timestamp: Box<TimestampFn>,
|
||||
}
|
||||
|
||||
impl<D: Decorator> Format<D> {
|
||||
/// New Format format that prints using color
|
||||
pub fn new(mode: FormatMode, d: D, fn_timestamp: Box<TimestampFn>) -> Self {
|
||||
Format {
|
||||
decorator: d,
|
||||
mode: mode,
|
||||
history: sync::Mutex::new(vec![]),
|
||||
fn_timestamp: fn_timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
// Returns `true` if message was not empty
|
||||
fn print_msg_header(&self,
|
||||
io: &mut io::Write,
|
||||
rd: &D::RecordDecorator,
|
||||
record: &Record)
|
||||
-> io::Result<bool> {
|
||||
try!(rd.fmt_timestamp(io, &*self.fn_timestamp));
|
||||
try!(rd.fmt_level(io,
|
||||
&|io: &mut io::Write| write!(io, " {} ", record.level().as_short_str())));
|
||||
|
||||
let mut writer = CountingWriter::new(io);
|
||||
try!(rd.fmt_msg(&mut writer, &|io| write!(io, "{}", record.msg())));
|
||||
Ok(writer.count() > 0)
|
||||
}
|
||||
|
||||
fn format_full(&self,
|
||||
io: &mut io::Write,
|
||||
record: &Record,
|
||||
logger_values: &OwnedKeyValueList)
|
||||
-> io::Result<()> {
|
||||
|
||||
let r_decorator = self.decorator.decorate(record);
|
||||
|
||||
|
||||
let mut comma_needed = try!(self.print_msg_header(io, &r_decorator, record));
|
||||
let mut serializer = Serializer::new(io, r_decorator);
|
||||
|
||||
for &(k, v) in record.values().iter().rev() {
|
||||
if comma_needed {
|
||||
try!(serializer.print_comma());
|
||||
}
|
||||
try!(v.serialize(record, k, &mut serializer));
|
||||
comma_needed |= true;
|
||||
}
|
||||
|
||||
for (k, v) in logger_values.iter() {
|
||||
if comma_needed {
|
||||
try!(serializer.print_comma());
|
||||
}
|
||||
try!(v.serialize(record, k, &mut serializer));
|
||||
comma_needed |= true;
|
||||
}
|
||||
|
||||
let (mut io, _decorator_r) = serializer.finish();
|
||||
|
||||
try!(write!(io, "\n"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn format_compact(&self,
|
||||
io: &mut io::Write,
|
||||
record: &Record,
|
||||
logger_values: &OwnedKeyValueList)
|
||||
-> io::Result<()> {
|
||||
|
||||
|
||||
let indent = try!(self.format_recurse(io, record, logger_values));
|
||||
|
||||
try!(self.print_indent(io, indent));
|
||||
|
||||
let r_decorator = self.decorator.decorate(record);
|
||||
let mut ser = Serializer::new(io, r_decorator);
|
||||
let mut comma_needed = try!(self.print_msg_header(ser.io, &ser.decorator, record));
|
||||
|
||||
for &(k, v) in record.values() {
|
||||
if comma_needed {
|
||||
try!(ser.print_comma());
|
||||
}
|
||||
try!(v.serialize(record, k, &mut ser));
|
||||
comma_needed |= true;
|
||||
}
|
||||
try!(write!(&mut ser.io, "\n"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_indent(&self, io: &mut io::Write, indent: usize) -> io::Result<()> {
|
||||
for _ in 0..indent {
|
||||
try!(write!(io, " "));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// record in the history, and check if should print
|
||||
// given set of values
|
||||
fn should_print(&self, line: &[u8], indent: usize) -> bool {
|
||||
let mut history = self.history.lock().unwrap();
|
||||
if history.len() <= indent {
|
||||
debug_assert_eq!(history.len(), indent);
|
||||
history.push(line.into());
|
||||
true
|
||||
} else {
|
||||
let should = history[indent] != line;
|
||||
if should {
|
||||
history[indent] = line.into();
|
||||
history.truncate(indent + 1);
|
||||
}
|
||||
should
|
||||
}
|
||||
}
|
||||
|
||||
/// Recursively format given `logger_values_ref`
|
||||
///
|
||||
/// Returns it's indent level
|
||||
fn format_recurse(&self,
|
||||
io : &mut io::Write,
|
||||
record: &slog::Record,
|
||||
logger_values_ref: &slog::OwnedKeyValueList)
|
||||
-> io::Result<usize> {
|
||||
let mut indent = if logger_values_ref.parent().is_none() {
|
||||
0
|
||||
} else {
|
||||
try!(self.format_recurse(io, record, logger_values_ref.parent().as_ref().unwrap()))
|
||||
};
|
||||
|
||||
|
||||
if let Some(logger_values) = logger_values_ref.values() {
|
||||
let res : io::Result<()> = TL_BUF.with(|line| {
|
||||
let mut line = line.borrow_mut();
|
||||
line.clear();
|
||||
let r_decorator = self.decorator.decorate(record);
|
||||
let mut ser = Serializer::new(&mut *line, r_decorator);
|
||||
|
||||
try!(self.print_indent(&mut ser.io, indent));
|
||||
let mut clean = true;
|
||||
let mut logger_values = logger_values;
|
||||
let mut kvs = vec!();
|
||||
loop {
|
||||
let (k, v) = logger_values.head();
|
||||
kvs.push((k, v));
|
||||
|
||||
logger_values = if let Some(v) = logger_values.tail() {
|
||||
v
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for &(k, v) in kvs.iter().rev() {
|
||||
if !clean {
|
||||
try!(ser.print_comma());
|
||||
}
|
||||
try!(v.serialize(record, k, &mut ser));
|
||||
clean = false;
|
||||
}
|
||||
|
||||
let (mut line, _) = ser.finish();
|
||||
|
||||
if self.should_print(line, indent) {
|
||||
try!(write!(line, "\n"));
|
||||
try!(io.write_all(line));
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
try!(res);
|
||||
indent += 1;
|
||||
}
|
||||
|
||||
Ok(indent)
|
||||
}
|
||||
}
|
||||
|
||||
fn severity_to_color(lvl: Level) -> u8 {
|
||||
match lvl {
|
||||
Level::Critical => 5,
|
||||
Level::Error => 1,
|
||||
Level::Warning => 3,
|
||||
Level::Info => 2,
|
||||
Level::Debug => 6,
|
||||
Level::Trace => 4,
|
||||
}
|
||||
}
|
||||
|
||||
/// Record decorator (color) for terminal output
|
||||
pub struct ColorDecorator {
|
||||
use_color: bool,
|
||||
}
|
||||
|
||||
impl ColorDecorator {
|
||||
/// New decorator that does color records
|
||||
pub fn new_colored() -> Self {
|
||||
ColorDecorator { use_color: true }
|
||||
}
|
||||
/// New decorator that does not color records
|
||||
pub fn new_plain() -> Self {
|
||||
ColorDecorator { use_color: false }
|
||||
}
|
||||
}
|
||||
|
||||
/// Particular record decorator (color) for terminal output
|
||||
pub struct ColorRecordDecorator {
|
||||
level_color: Option<u8>,
|
||||
key_bold: bool,
|
||||
}
|
||||
|
||||
|
||||
impl Decorator for ColorDecorator {
|
||||
type RecordDecorator = ColorRecordDecorator;
|
||||
|
||||
fn decorate(&self, record: &Record) -> ColorRecordDecorator {
|
||||
if self.use_color {
|
||||
ColorRecordDecorator {
|
||||
level_color: Some(severity_to_color(record.level())),
|
||||
key_bold: true,
|
||||
}
|
||||
} else {
|
||||
ColorRecordDecorator {
|
||||
level_color: None,
|
||||
key_bold: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl RecordDecorator for ColorRecordDecorator {
|
||||
fn fmt_level(&self,
|
||||
io: &mut io::Write,
|
||||
f: &Fn(&mut io::Write) -> io::Result<()>)
|
||||
-> io::Result<()> {
|
||||
if let Some(level_color) = self.level_color {
|
||||
try!(write!(io, "\x1b[3{}m", level_color));
|
||||
try!(f(io));
|
||||
try!(write!(io, "\x1b[39m"));
|
||||
} else {
|
||||
try!(f(io));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn fmt_msg(&self,
|
||||
io: &mut io::Write,
|
||||
f: &Fn(&mut io::Write) -> io::Result<()>)
|
||||
-> io::Result<()> {
|
||||
if self.key_bold {
|
||||
let before = |io: &mut io::Write| write!(io, "\x1b[1m");
|
||||
let after = |io: &mut io::Write| write!(io, "\x1b[0m");
|
||||
let mut wrapper = SurroundingWriter::new(io, &before, &after);
|
||||
try!(f(&mut wrapper));
|
||||
try!(wrapper.finish());
|
||||
} else {
|
||||
try!(f(io));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fmt_key(&self,
|
||||
io: &mut io::Write,
|
||||
f: &Fn(&mut io::Write) -> io::Result<()>)
|
||||
-> io::Result<()> {
|
||||
self.fmt_msg(io, f)
|
||||
}
|
||||
}
|
||||
|
||||
struct Serializer<W, D: RecordDecorator> {
|
||||
io: W,
|
||||
decorator: D,
|
||||
}
|
||||
|
||||
impl<W: io::Write, D: RecordDecorator> Serializer<W, D> {
|
||||
fn new(io: W, d: D) -> Self {
|
||||
Serializer {
|
||||
io: io,
|
||||
decorator: d,
|
||||
}
|
||||
}
|
||||
|
||||
fn print_comma(&mut self) -> io::Result<()> {
|
||||
try!(self.decorator.fmt_separator(&mut self.io, &|io: &mut io::Write| write!(io, ", ")));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn finish(self) -> (W, D) {
|
||||
(self.io, self.decorator)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! s(
|
||||
($s:expr, $k:expr, $v:expr) => {
|
||||
try!($s.decorator.fmt_key(&mut $s.io, &|io : &mut io::Write| write!(io, "{}", $k)));
|
||||
try!($s.decorator.fmt_separator(&mut $s.io, &|io : &mut io::Write| write!(io, ": ")));
|
||||
try!($s.decorator.fmt_value(&mut $s.io, &|io : &mut io::Write| write!(io, "{}", $v)));
|
||||
};
|
||||
);
|
||||
|
||||
|
||||
impl<W: io::Write, D: RecordDecorator> slog::ser::Serializer for Serializer<W, D> {
|
||||
fn emit_none(&mut self, key: &str) -> ser::Result {
|
||||
s!(self, key, "None");
|
||||
Ok(())
|
||||
}
|
||||
fn emit_unit(&mut self, key: &str) -> ser::Result {
|
||||
s!(self, key, "()");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn emit_bool(&mut self, key: &str, val: bool) -> ser::Result {
|
||||
s!(self, key, val);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn emit_char(&mut self, key: &str, val: char) -> ser::Result {
|
||||
s!(self, key, val);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn emit_usize(&mut self, key: &str, val: usize) -> ser::Result {
|
||||
s!(self, key, val);
|
||||
Ok(())
|
||||
}
|
||||
fn emit_isize(&mut self, key: &str, val: isize) -> ser::Result {
|
||||
s!(self, key, val);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn emit_u8(&mut self, key: &str, val: u8) -> ser::Result {
|
||||
s!(self, key, val);
|
||||
Ok(())
|
||||
}
|
||||
fn emit_i8(&mut self, key: &str, val: i8) -> ser::Result {
|
||||
s!(self, key, val);
|
||||
Ok(())
|
||||
}
|
||||
fn emit_u16(&mut self, key: &str, val: u16) -> ser::Result {
|
||||
s!(self, key, val);
|
||||
Ok(())
|
||||
}
|
||||
fn emit_i16(&mut self, key: &str, val: i16) -> ser::Result {
|
||||
s!(self, key, val);
|
||||
Ok(())
|
||||
}
|
||||
fn emit_u32(&mut self, key: &str, val: u32) -> ser::Result {
|
||||
s!(self, key, val);
|
||||
Ok(())
|
||||
}
|
||||
fn emit_i32(&mut self, key: &str, val: i32) -> ser::Result {
|
||||
s!(self, key, val);
|
||||
Ok(())
|
||||
}
|
||||
fn emit_f32(&mut self, key: &str, val: f32) -> ser::Result {
|
||||
s!(self, key, val);
|
||||
Ok(())
|
||||
}
|
||||
fn emit_u64(&mut self, key: &str, val: u64) -> ser::Result {
|
||||
s!(self, key, val);
|
||||
Ok(())
|
||||
}
|
||||
fn emit_i64(&mut self, key: &str, val: i64) -> ser::Result {
|
||||
s!(self, key, val);
|
||||
Ok(())
|
||||
}
|
||||
fn emit_f64(&mut self, key: &str, val: f64) -> ser::Result {
|
||||
s!(self, key, val);
|
||||
Ok(())
|
||||
}
|
||||
fn emit_str(&mut self, key: &str, val: &str) -> ser::Result {
|
||||
s!(self, key, val);
|
||||
Ok(())
|
||||
}
|
||||
fn emit_arguments(&mut self, key: &str, val: &fmt::Arguments) -> ser::Result {
|
||||
s!(self, key, val);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Decorator + Send + Sync> StreamFormat for Format<D> {
|
||||
fn format(&self,
|
||||
io: &mut io::Write,
|
||||
record: &Record,
|
||||
logger_values: &OwnedKeyValueList)
|
||||
-> io::Result<()> {
|
||||
match self.mode {
|
||||
FormatMode::Compact => self.format_compact(io, record, logger_values),
|
||||
FormatMode::Full => self.format_full(io, record, logger_values),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const TIMESTAMP_FORMAT: &'static str = "%b %d %H:%M:%S%.3f";
|
||||
|
||||
/// Default local timestamp function used by `Format`
|
||||
///
|
||||
/// The exact format used, is still subject to change.
|
||||
pub fn timestamp_local(io: &mut io::Write) -> io::Result<()> {
|
||||
write!(io, "{}", chrono::Local::now().format(TIMESTAMP_FORMAT))
|
||||
}
|
||||
|
||||
/// Default UTC timestamp function used by `Format`
|
||||
///
|
||||
/// The exact format used, is still subject to change.
|
||||
pub fn timestamp_utc(io: &mut io::Write) -> io::Result<()> {
|
||||
write!(io, "{}", chrono::UTC::now().format(TIMESTAMP_FORMAT))
|
||||
}
|
||||
|
||||
/// Streamer builder
|
||||
pub struct StreamerBuilder {
|
||||
color: Option<bool>, // None = auto
|
||||
stdout: bool,
|
||||
async: bool,
|
||||
mode: FormatMode,
|
||||
fn_timestamp: Box<TimestampFn>,
|
||||
}
|
||||
|
||||
impl StreamerBuilder {
|
||||
/// New `StreamerBuilder`
|
||||
pub fn new() -> Self {
|
||||
StreamerBuilder {
|
||||
color: None,
|
||||
stdout: true,
|
||||
async: false,
|
||||
mode: FormatMode::Full,
|
||||
fn_timestamp: Box::new(timestamp_local),
|
||||
}
|
||||
}
|
||||
|
||||
/// Force colored output
|
||||
pub fn color(mut self) -> Self {
|
||||
self.color = Some(true);
|
||||
self
|
||||
}
|
||||
|
||||
/// Force plain output
|
||||
pub fn plain(mut self) -> Self {
|
||||
self.color = Some(false);
|
||||
self
|
||||
}
|
||||
|
||||
/// Auto detect color (default)
|
||||
pub fn auto_color(mut self) -> Self {
|
||||
self.color = None;
|
||||
self
|
||||
}
|
||||
|
||||
/// Output to stderr
|
||||
pub fn stderr(mut self) -> Self {
|
||||
self.stdout = false;
|
||||
self
|
||||
}
|
||||
|
||||
/// Output to stdout (default)
|
||||
pub fn stdout(mut self) -> Self {
|
||||
self.stdout = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Output using full mode
|
||||
pub fn full(mut self) -> Self {
|
||||
self.mode = FormatMode::Full;
|
||||
self
|
||||
}
|
||||
|
||||
/// Output using compact mode (default)
|
||||
pub fn compact(mut self) -> Self {
|
||||
self.mode = FormatMode::Compact;
|
||||
self
|
||||
}
|
||||
|
||||
/// Use asynchronous streamer
|
||||
pub fn async(mut self) -> Self {
|
||||
self.async = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Use synchronous streamer (default)
|
||||
pub fn sync(mut self) -> Self {
|
||||
self.async = false;
|
||||
self
|
||||
}
|
||||
|
||||
/// Use the UTC time zone for the timestamp
|
||||
pub fn use_utc_timestamp(mut self) -> Self {
|
||||
self.fn_timestamp = Box::new(timestamp_utc);
|
||||
self
|
||||
}
|
||||
|
||||
/// Use the local time zone for the timestamp (default)
|
||||
pub fn use_local_timestamp(mut self) -> Self {
|
||||
self.fn_timestamp = Box::new(timestamp_local);
|
||||
self
|
||||
}
|
||||
|
||||
/// Provide a custom function to generate the timestamp
|
||||
pub fn use_custom_timestamp<F>(mut self, f: F) -> Self
|
||||
where F: Fn(&mut io::Write) -> io::Result<()> + 'static + Send + Sync
|
||||
{
|
||||
self.fn_timestamp = Box::new(f);
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the streamer
|
||||
pub fn build(self) -> Box<slog::Drain<Error = io::Error> + Send + Sync> {
|
||||
let color = self.color.unwrap_or(if self.stdout {
|
||||
stdout_isatty()
|
||||
} else {
|
||||
stderr_isatty()
|
||||
});
|
||||
|
||||
let format = Format::new(self.mode,
|
||||
ColorDecorator { use_color: color },
|
||||
self.fn_timestamp);
|
||||
|
||||
let io = if self.stdout {
|
||||
Box::new(io::stdout()) as Box<io::Write + Send>
|
||||
} else {
|
||||
Box::new(io::stderr()) as Box<io::Write + Send>
|
||||
};
|
||||
|
||||
if self.async {
|
||||
Box::new(async_stream(io, format))
|
||||
} else {
|
||||
Box::new(stream(io, format))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for StreamerBuilder {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// Build `slog_stream::Streamer`/`slog_stream::AsyncStreamer` that
|
||||
/// will output logging records to stderr/stderr.
|
||||
pub fn streamer() -> StreamerBuilder {
|
||||
StreamerBuilder::new()
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
{"files":{".cargo/config":"b1d2b4fdf0d7fcfa75533a98408cfad4a537048ce0cd7ac72027d0feda4126b6",".travis.yml":"a9c415cf334e2a854281337d5287cad4990178ae1c4f7d4e17c3aed4f20ba0b4","CHANGELOG.md":"a8de74f313235275bcb16143ef3d379050e396ed509bf0b03b06165f8644f0ea","Cargo.toml":"276ee9cc214c9b9b476b1ec916f4b1008a1820ce69f4a454d118f6958bb47d4a","LICENSE-MPL2":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","Makefile":"a8bb2d458c5e2a58be185209143165182e9bb353e097ef752caea500b2c46892","README.md":"350d15b5cf70a84fd1fc9be995881ae4d4bbfbafd825c42a4589aebf79cc4c25","benches.txt":"dd19c2f77e35973a0bf28ec289652436e9709dcb90536ac447c5ed62d9a8a68e","examples.txt":"6939adf8563bd6657a4194f02ed7aa04ce7e88a377351e90d32729a5bcfae3bb","rusty-tags.vi":"1b8c898a4b26fcafb934e1a6a5d29141c63c9b826763dd8a44dc58e4f524e1d6","src/_drain.rs":"7dee5308c5abd351dd77b10cdcc79f1fe5a6914cfd96d18ccce6f434f3ab52ad","src/_level.rs":"2d6eba54b7e7dc72c988e8205a0fda52570f41210e43325220286d05da01ef82","src/_logger.rs":"3cedb65d7718738e635bdb08addbfc1f878f28d0d83ef50badf25e52f3d92da5","src/lib.rs":"acab0d836f6e0a4313fb977c16a1ca72b845f5f6993c636499e4fd15e903fd33","src/ser.rs":"4cb0d46f7ea8e5d0c8ff2a8469dcbd188d7232b1652014e82bf51c2b1cbfcf7e","src/tests.rs":"b34f2279d7d1111300bc1965c2760bd3485cf49cfda70dd10030b6a8abbfa842"},"package":"5b965551440d867da261b10d50871ae608537c56fbeb872a296b12add733acf1"}
|
|
@ -1 +0,0 @@
|
|||
paths = [ "." ]
|
|
@ -1,31 +0,0 @@
|
|||
language: rust
|
||||
rust:
|
||||
- stable
|
||||
- 1.12.0
|
||||
- beta
|
||||
- nightly
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq graphviz
|
||||
|
||||
script:
|
||||
- make all
|
||||
- make travistest
|
||||
- if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then make bench ; fi
|
||||
- if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then cargo build --no-default-features; fi
|
||||
|
||||
env:
|
||||
global:
|
||||
- RUST_BACKTRACE=1
|
||||
matrix:
|
||||
-
|
||||
- RELEASE=true
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/87a331e1a21456b6e2ad
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
on_failure: change # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
|
@ -1,70 +0,0 @@
|
|||
**Note:** `slog-*` sub-crates have their own ChangeLog files under
|
||||
corresponding `crates/*/` directory.
|
||||
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 1.6.0 - 2017-10-19
|
||||
### Changed
|
||||
|
||||
* *Breaking*: `fmt::Arguments<'static>` should not be `Sync` -
|
||||
https://github.com/slog-rs/slog/pull/148
|
||||
|
||||
## 1.5.0 - 2017-01-19
|
||||
### Changed
|
||||
|
||||
* Order of key-value pairs is now strictly defined
|
||||
|
||||
## 1.4.1 - 2017-01-19
|
||||
### Changed
|
||||
|
||||
* Fix an invalid syntax exposed by nightly rust change (Issue #103)
|
||||
|
||||
## 1.4.0 - 2016-12-27
|
||||
### Changed
|
||||
|
||||
* Deprecate `OwnedKeyValueList::id`
|
||||
* Updated documentation
|
||||
|
||||
## 1.3.2 - 2016-11-19
|
||||
### Added
|
||||
|
||||
* `slog_o` as an alternative name for `o`
|
||||
|
||||
## 1.3.1 - 2016-11-19
|
||||
|
||||
Cargo publishing mistake.
|
||||
|
||||
## 1.3.0 - 2016-10-31
|
||||
### Changed
|
||||
|
||||
* **BREAKING**: Removed `Send+Sync` from `Drain`
|
||||
|
||||
## 1.2.1 - 2016-10-27
|
||||
### Added
|
||||
|
||||
* `OwnedKeyValueList::id` for owned key value unique identification
|
||||
|
||||
## 1.2.0 - 2016-10-21
|
||||
### Changed
|
||||
|
||||
* **BREAKING**: `Serializer` takes `key : &'static str` now
|
||||
* Fixed corner cases in `info!(...)` and other macros
|
||||
|
||||
## 1.1.0 - 2016-10-17
|
||||
### Changed
|
||||
|
||||
* **BREAKING**: Rewrite handling of owned values.
|
||||
|
||||
## 1.0.1
|
||||
### Changed
|
||||
|
||||
* Fix `use std` in `o!`
|
||||
* Implement `fmt::Debug` for `Logger`
|
||||
|
||||
## 1.0.0 - 2016-09-21
|
||||
|
||||
First stable release.
|
|
@ -1,51 +0,0 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "slog"
|
||||
version = "1.6.0"
|
||||
authors = ["Dawid Ciężarkiewicz <dpc@dpc.pw>"]
|
||||
description = "Structured, composable logging for Rust"
|
||||
homepage = "https://github.com/slog-rs/slog"
|
||||
documentation = "https://docs.rs/slog"
|
||||
readme = "README.md"
|
||||
keywords = ["log", "logging", "structured", "hierarchical"]
|
||||
categories = ["development-tools::debugging"]
|
||||
license = "MPL-2.0"
|
||||
repository = "https://github.com/slog-rs/slog"
|
||||
[profile.bench]
|
||||
opt-level = 3
|
||||
lto = true
|
||||
debug = false
|
||||
debug-assertions = false
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
lto = true
|
||||
debug = false
|
||||
debug-assertions = false
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
max_level_debug = []
|
||||
release_max_level_off = []
|
||||
release_max_level_warn = []
|
||||
max_level_warn = []
|
||||
max_level_info = []
|
||||
max_level_off = []
|
||||
release_max_level_debug = []
|
||||
max_level_trace = []
|
||||
max_level_error = []
|
||||
release_max_level_info = []
|
||||
release_max_level_trace = []
|
||||
release_max_level_error = []
|
||||
std = []
|
|
@ -1,373 +0,0 @@
|
|||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
|
@ -1,79 +0,0 @@
|
|||
PKG_NAME=$(shell grep name Cargo.toml | head -n 1 | awk -F \" '{print $$2}')
|
||||
DOCS_DEFAULT_MODULE=$(subst -,_,$(PKG_NAME))
|
||||
ifeq (, $(shell which cargo-check 2> /dev/null))
|
||||
DEFAULT_TARGET=build
|
||||
else
|
||||
DEFAULT_TARGET=build
|
||||
endif
|
||||
|
||||
default: $(DEFAULT_TARGET)
|
||||
|
||||
CARGO_FLAGS += -v
|
||||
|
||||
ALL_TARGETS += build $(EXAMPLES) test doc crates
|
||||
ifneq ($(RELEASE),)
|
||||
$(info RELEASE BUILD: $(PKG_NAME))
|
||||
CARGO_FLAGS += --release
|
||||
else
|
||||
$(info DEBUG BUILD: $(PKG_NAME); use `RELEASE=true make [args]` for release build)
|
||||
endif
|
||||
|
||||
EXAMPLES = $(shell cd examples 2>/dev/null && ls *.rs 2>/dev/null | sed -e 's/.rs$$//g' )
|
||||
CRATES = $(shell cd crates 2>/dev/null && ls 2>/dev/null)
|
||||
|
||||
all: $(ALL_TARGETS)
|
||||
|
||||
.PHONY: run test build doc clean clippy
|
||||
run test build clean:
|
||||
cargo $@ $(CARGO_FLAGS)
|
||||
|
||||
check:
|
||||
$(info Running check; use `make build` to actually build)
|
||||
cargo $@ $(CARGO_FLAGS)
|
||||
|
||||
clippy:
|
||||
cargo build --features clippy
|
||||
|
||||
.PHONY: bench
|
||||
bench:
|
||||
cargo $@ $(filter-out --release,$(CARGO_FLAGS))
|
||||
|
||||
.PHONY: travistest
|
||||
travistest: test
|
||||
|
||||
.PHONY: longtest
|
||||
longtest:
|
||||
@echo "Running longtest. Press Ctrl+C to stop at any time"
|
||||
@sleep 2
|
||||
@i=0; while i=$$((i + 1)) && echo "Iteration $$i" && make test ; do :; done
|
||||
|
||||
.PHONY: $(EXAMPLES)
|
||||
$(EXAMPLES):
|
||||
cargo build --example $@ $(CARGO_FLAGS)
|
||||
|
||||
.PHONY: crates
|
||||
crates: $(CRATES)
|
||||
|
||||
.PHONY: $(CRATES)
|
||||
$(CRATES):
|
||||
cd "crates/$@"; cargo build $(CARGO_FLAGS)
|
||||
cd "crates/$@"; cargo test $(CARGO_FLAGS)
|
||||
|
||||
.PHONY: doc
|
||||
doc: FORCE
|
||||
cargo doc
|
||||
|
||||
.PHONY: publishdoc
|
||||
publishdoc:
|
||||
rm -rf target/doc
|
||||
make doc
|
||||
echo '<meta http-equiv="refresh" content="0;url='${DOCS_DEFAULT_MODULE}'/index.html">' > target/doc/index.html
|
||||
ghp-import -n target/doc
|
||||
git push -f origin gh-pages
|
||||
|
||||
.PHONY: docview
|
||||
docview: doc
|
||||
xdg-open target/doc/$(PKG_NAME)/index.html
|
||||
|
||||
.PHONY: FORCE
|
||||
FORCE:
|
|
@ -1,164 +0,0 @@
|
|||
<p align="center">
|
||||
|
||||
<a href="https://github.com/slog-rs/slog">
|
||||
<img src="https://cdn.rawgit.com/slog-rs/misc/master/media/slog.svg" alt="slog-rs logo">
|
||||
</a>
|
||||
<br>
|
||||
|
||||
<a href="https://travis-ci.org/slog-rs/slog">
|
||||
<img src="https://img.shields.io/travis/slog-rs/slog/master.svg" alt="Travis CI Build Status">
|
||||
</a>
|
||||
|
||||
<a href="https://crates.io/crates/slog">
|
||||
<img src="https://img.shields.io/crates/d/slog.svg" alt="slog-rs on crates.io">
|
||||
</a>
|
||||
|
||||
<a href="https://gitter.im/slog-rs/slog">
|
||||
<img src="https://img.shields.io/gitter/room/slog-rs/slog.svg" alt="slog-rs Gitter Chat">
|
||||
</a>
|
||||
|
||||
<a href="https://docs.rs/releases/search?query=slog-">
|
||||
<img src="https://docs.rs/slog/badge.svg" alt="docs-rs: release versions documentation">
|
||||
</a>
|
||||
<br>
|
||||
<strong><a href="https://github.com/slog-rs/slog/wiki/Getting-started">Getting started</a></strong>
|
||||
|
||||
<a href="//github.com/slog-rs/slog/wiki/Introduction-to-structured-logging-with-slog">Introduction</a>
|
||||
|
||||
<a href="//github.com/slog-rs/slog/wiki/FAQ">FAQ</a>
|
||||
<br>
|
||||
<a href="https://crates.io/search?q=slog">Crate list</a>
|
||||
</p>
|
||||
|
||||
# slog-rs - The Logging for [Rust][rust]
|
||||
|
||||
### Table of Contents
|
||||
|
||||
* [Status & news](#status--news)
|
||||
* [`slog` crate](#slog-crate)
|
||||
* [Features](#features)
|
||||
* [Advantages over log crate](#advantages-over-log-crate)
|
||||
* [Terminal output example](#terminal-output-example)
|
||||
* [Using & help](#using--help)
|
||||
* [Compatibility Policy](#compatibility-policy)
|
||||
* [Slog community](#slog-community)
|
||||
* [Overview](#overview)
|
||||
* [Slog related resources](#slog-related-resources)
|
||||
|
||||
### Status & news
|
||||
|
||||
`slog` is an ecosystem of reusable components for structured, extensible,
|
||||
composable logging for [Rust][rust].
|
||||
|
||||
The ambition is to be The Logging Framework for Rust. `slog` should accommodate
|
||||
variety of logging features and requirements.
|
||||
|
||||
### Features & technical documentation
|
||||
|
||||
Most of interesting documentation is using rustdoc itself.
|
||||
|
||||
You can view on [docs.rs/slog](https://docs.rs/slog/1/)
|
||||
|
||||
### Terminal output example
|
||||
|
||||
`slog-term` is only one of many `slog` features - useful showcase.
|
||||
|
||||
Automatic TTY detection and colors:
|
||||
|
||||
![slog-rs terminal full-format output](http://i.imgur.com/IUe80gU.png)
|
||||
|
||||
Compact vs full mode:
|
||||
|
||||
![slog-rs terminal compact output](http://i.imgur.com/P9u2sWP.png)
|
||||
![slog-rs terminal full output](http://i.imgur.com/ENiy5H9.png)
|
||||
|
||||
|
||||
## Using & help
|
||||
|
||||
See
|
||||
[examples/features.rs](https://github.com/slog-rs/misc/blob/master/examples/features.rs)
|
||||
for full quick code example overview.
|
||||
|
||||
See [faq] for answers to common questions and [wiki] for other documentation
|
||||
articles. If you want to say hi, or need help use [slog-rs gitter] channel.
|
||||
|
||||
Read [Documentation](https://docs.rs/slog/) for details and features.
|
||||
|
||||
To report a bug or ask for features use [github issues][issues].
|
||||
|
||||
[faq]: https://github.com/slog-rs/slog/wiki/FAQ
|
||||
[wiki]: https://github.com/slog-rs/slog/wiki/
|
||||
[rust]: http://rust-lang.org
|
||||
[slog-rs gitter]: https://gitter.im/slog-rs/slog
|
||||
[issues]: //github.com/slog-rs/slog/issues
|
||||
|
||||
#### In your project
|
||||
|
||||
In Cargo.toml:
|
||||
|
||||
```
|
||||
[dependencies]
|
||||
slog = "1.2"
|
||||
```
|
||||
|
||||
In your `main.rs`:
|
||||
|
||||
```
|
||||
#[macro_use]
|
||||
extern crate slog;
|
||||
```
|
||||
|
||||
### Compatibility Policy
|
||||
|
||||
`slog` follows SemVer: this is the official policy regarding breaking changes
|
||||
and minimum required versions of Rust.
|
||||
|
||||
Slog crates should pin minimum required version of Rust to the CI builds.
|
||||
Bumping the minimum version of Rust is considered a minor breaking change,
|
||||
meaning *at a minimum* the minor version will be bumped.
|
||||
|
||||
In order to keep from being surprised of breaking changes, it is **highly**
|
||||
recommended to use the `~major.minor.patch` style in your `Cargo.toml` if you
|
||||
wish to target a version of Rust that is *older* than current stable minus two
|
||||
releases:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
slog = "~1.3.0"
|
||||
```
|
||||
|
||||
This will cause *only* the patch version to be updated upon a `cargo update`
|
||||
call, and therefore cannot break due to new features, or bumped minimum
|
||||
versions of Rust.
|
||||
|
||||
#### Minimum Version of Rust
|
||||
|
||||
`slog` and it's ecosystem officially supports current stable Rust, minus
|
||||
two releases, but may work with prior releases as well. For example, current
|
||||
stable Rust at the time of this writing is 1.13.0, meaning `slog` is guaranteed
|
||||
to compile with 1.11.0 and beyond. At the 1.14.0 release, `slog` will be
|
||||
guaranteed to compile with 1.12.0 and beyond, etc.
|
||||
|
||||
Upon bumping the minimum version of Rust (assuming it's within the stable-2
|
||||
range), it *must* be clearly annotated in the `CHANGELOG.md`
|
||||
|
||||
|
||||
## Slog community
|
||||
|
||||
### Overview
|
||||
|
||||
Slog related crates are hosted under [slog github
|
||||
organization](https://github.com/slog-rs).
|
||||
|
||||
Dawid Ciężarkiewicz is the original author and current maintainer of `slog` and
|
||||
therefore self-appointed benevolent dictator over the project. When working on
|
||||
slog Dawid follows and expects everyone to follow his [Code of
|
||||
Conduct](https://github.com/dpc/public/blob/master/COC.md).
|
||||
|
||||
Any particular repositories under slog ecosystem might be created, controlled,
|
||||
maintained by other entities with various level of autonomy. Lets work together
|
||||
toward a common goal in respectful and welcoming atmosphere!
|
||||
|
||||
## slog-related articles
|
||||
|
||||
* [24 days of Rust - structured logging](https://siciarz.net/24-days-rust-structured-logging/) - review and tutorial by Zbigniew Siciarz 2016-12-05
|
|
@ -1 +0,0 @@
|
|||
Benchmarks have been moved to: https://github.com/slog-rs/misc/tree/master/benches
|
|
@ -1 +0,0 @@
|
|||
Examples have been moved to: https://github.com/slog-rs/misc/tree/master/examples
|
|
@ -1,459 +0,0 @@
|
|||
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
|
||||
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
||||
ASCII_LOWERCASE_MAP /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^static ASCII_LOWERCASE_MAP: [u8; 256] =$/;" c
|
||||
AnyTerminal /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^enum AnyTerminal {$/;" g
|
||||
AsFmtSerializer /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^struct AsFmtSerializer<F>(pub F)$/;" s
|
||||
Async /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^impl Async {$/;" i
|
||||
Async /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^pub struct Async {$/;" s
|
||||
AsyncBuilder /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^impl<D> AsyncBuilder<D>$/;" i
|
||||
AsyncBuilder /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^pub struct AsyncBuilder<D>$/;" s
|
||||
AsyncCore /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^impl AsyncCore {$/;" i
|
||||
AsyncCore /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^pub struct AsyncCore {$/;" s
|
||||
AsyncCoreBuilder /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^impl<D> AsyncCoreBuilder<D>$/;" i
|
||||
AsyncCoreBuilder /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^pub struct AsyncCoreBuilder<D>$/;" s
|
||||
AsyncError /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^pub enum AsyncError {$/;" g
|
||||
AsyncGuard /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^pub struct AsyncGuard {$/;" s
|
||||
AsyncMsg /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^enum AsyncMsg {$/;" g
|
||||
AsyncRecord /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^struct AsyncRecord {$/;" s
|
||||
AsyncResult /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^pub type AsyncResult<T> = std::result::Result<T, AsyncError>;$/;" T
|
||||
BorrowedKV /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct BorrowedKV<'a>($/;" s
|
||||
CheckOwned /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^ struct CheckOwned;$/;" s
|
||||
CompactFormat /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<D> CompactFormat<D>$/;" i
|
||||
CompactFormat /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub struct CompactFormat<D>$/;" s
|
||||
CompactFormatBuilder /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<D> CompactFormatBuilder<D>$/;" i
|
||||
CompactFormatBuilder /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub struct CompactFormatBuilder<D>$/;" s
|
||||
CompactFormatSerializer /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<'a> CompactFormatSerializer<'a> {$/;" i
|
||||
CompactFormatSerializer /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^struct CompactFormatSerializer<'a> {$/;" s
|
||||
CountingWriter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<'a> CountingWriter<'a> {$/;" i
|
||||
CountingWriter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^struct CountingWriter<'a> {$/;" s
|
||||
Decorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub trait Decorator {$/;" t
|
||||
Decorator for Box /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<T: ?Sized> Decorator for Box<T>$/;" i
|
||||
Decorator for PlainDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<W> Decorator for PlainDecorator<W>$/;" i
|
||||
Decorator for PlainSyncDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<W> Decorator for PlainSyncDecorator<W>$/;" i
|
||||
Decorator for TermDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl Decorator for TermDecorator {$/;" i
|
||||
Discard /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct Discard;$/;" s
|
||||
Drain /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub trait Drain {$/;" t
|
||||
Drain for Arc /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D: Drain + ?Sized> Drain for Arc<D> {$/;" i
|
||||
Drain for Async /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^impl Drain for Async {$/;" i
|
||||
Drain for AsyncCore /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^impl Drain for AsyncCore {$/;" i
|
||||
Drain for Box /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D: Drain + ?Sized> Drain for Box<D> {$/;" i
|
||||
Drain for CheckOwned /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^ impl Drain for CheckOwned {$/;" i
|
||||
Drain for CompactFormat /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<D> Drain for CompactFormat<D>$/;" i
|
||||
Drain for Discard /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl Drain for Discard {$/;" i
|
||||
Drain for Duplicate /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D1: Drain, D2: Drain> Drain for Duplicate<D1, D2> {$/;" i
|
||||
Drain for Filter /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D: Drain, F> Drain for Filter<D, F>$/;" i
|
||||
Drain for FullFormat /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<D> Drain for FullFormat<D>$/;" i
|
||||
Drain for Fuse /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D: Drain> Drain for Fuse<D>$/;" i
|
||||
Drain for IgnoreResult /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D: Drain> Drain for IgnoreResult<D> {$/;" i
|
||||
Drain for LevelFilter /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D: Drain> Drain for LevelFilter<D> {$/;" i
|
||||
Drain for Logger /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D> Drain for Logger<D>$/;" i
|
||||
Drain for MapError /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D: Drain, E> Drain for MapError<D, E> {$/;" i
|
||||
Drain for std /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D: Drain> Drain for std::sync::Mutex<D> {$/;" i
|
||||
Drop for Async /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^impl Drop for Async {$/;" i
|
||||
Drop for AsyncCore /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^impl Drop for AsyncCore {$/;" i
|
||||
Drop for AsyncGuard /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^impl Drop for AsyncGuard {$/;" i
|
||||
Drop for PlainRecordDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<'a, W> Drop for PlainRecordDecorator<'a, W>$/;" i
|
||||
Drop for PlainSyncRecordDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<W> Drop for PlainSyncRecordDecorator<W>$/;" i
|
||||
Drop for PushFnValueSerializer /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<'a> Drop for PushFnValueSerializer<'a> {$/;" i
|
||||
Drop for Serializer /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<'a> Drop for Serializer<'a> {$/;" i
|
||||
Drop for TermRecordDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<'a> Drop for TermRecordDecorator<'a> {$/;" i
|
||||
Duplicate /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D1: Drain, D2: Drain> Duplicate<D1, D2> {$/;" i
|
||||
Duplicate /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct Duplicate<D1: Drain, D2: Drain>(pub D1, pub D2);$/;" s
|
||||
Err /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ type Err = AsyncError;$/;" T
|
||||
Err /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ type Err = io::Error;$/;" T
|
||||
Err /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ type Err = ($/;" T
|
||||
Err /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ type Err = ();$/;" T
|
||||
Err /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ type Err = D::Err;$/;" T
|
||||
Err /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ type Err = E;$/;" T
|
||||
Err /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ type Err = MutexDrainError<D>;$/;" T
|
||||
Err /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ type Err = Never;$/;" T
|
||||
Err /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ type Err;$/;" T
|
||||
Err /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^ type Err = Never;$/;" T
|
||||
Error /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub enum Error {$/;" g
|
||||
Filter /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D: Drain, F> Filter<D, F>$/;" i
|
||||
Filter /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct Filter<D: Drain, F>(pub D, pub F)$/;" s
|
||||
FilterFn /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub trait FilterFn$/;" t
|
||||
FilterFn /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub trait FilterFn: 'static + Sync + Send + Fn(&Record) -> bool {}$/;" t
|
||||
FilterFn for T /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T> FilterFn for T$/;" i
|
||||
FilterLevel /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl FilterLevel {$/;" i
|
||||
FilterLevel /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub enum FilterLevel {$/;" g
|
||||
FnValue /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct FnValue<V: Value, F>(pub F)$/;" s
|
||||
Foo /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^ impl Foo {$/;" i
|
||||
Foo /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^ struct Foo;$/;" s
|
||||
From /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^impl<T> From<mpsc::TrySendError<T>> for AsyncError {$/;" i
|
||||
From /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^impl<T> From<std::sync::PoisonError<T>> for AsyncError {$/;" i
|
||||
From /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^impl<T> From<std::sync::TryLockError<T>> for AsyncError {$/;" i
|
||||
From /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<'a, D: Drain> From<std::sync::PoisonError<std::sync::MutexGuard<'a, D>>>$/;" i
|
||||
From for Error /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl From<core::fmt::Error> for Error {$/;" i
|
||||
From for Error /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl From<std::io::Error> for Error {$/;" i
|
||||
From for std /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl From<Error> for std::io::Error {$/;" i
|
||||
FromStr for FilterLevel /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl FromStr for FilterLevel {$/;" i
|
||||
FromStr for Level /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl FromStr for Level {$/;" i
|
||||
FullFormat /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<D> FullFormat<D>$/;" i
|
||||
FullFormat /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub struct FullFormat<D>$/;" s
|
||||
FullFormatBuilder /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<D> FullFormatBuilder<D>$/;" i
|
||||
FullFormatBuilder /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub struct FullFormatBuilder<D>$/;" s
|
||||
Fuse /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D: Drain> Fuse<D>$/;" i
|
||||
Fuse /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct Fuse<D: Drain>(pub D)$/;" s
|
||||
IgnoreResult /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D: Drain> IgnoreResult<D> {$/;" i
|
||||
IgnoreResult /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct IgnoreResult<D: Drain> {$/;" s
|
||||
K /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^ struct K;$/;" s
|
||||
KV /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl KV for () {$/;" i
|
||||
KV /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<'a, T> KV for &'a T$/;" i
|
||||
KV /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T: KV, R: KV> KV for (T, R) {$/;" i
|
||||
KV /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub trait KV {$/;" t
|
||||
KV for Arc /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T> KV for Arc<T>$/;" i
|
||||
KV for BorrowedKV /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<'a> KV for BorrowedKV<'a> {$/;" i
|
||||
KV for Box /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T> KV for Box<T>$/;" i
|
||||
KV for K /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^ impl KV for K {$/;" i
|
||||
KV for MultiListNode /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl KV for MultiListNode {$/;" i
|
||||
KV for OwnedKV /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T> KV for OwnedKV<T>$/;" i
|
||||
KV for OwnedKVList /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl KV for OwnedKVList {$/;" i
|
||||
KV for OwnedKVListNode /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T> KV for OwnedKVListNode<T>$/;" i
|
||||
KV for SingleKV /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<V> KV for SingleKV<V>$/;" i
|
||||
Key /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub type Key = &'static str;$/;" T
|
||||
LOC /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ static LOC : $crate::RecordLocation = $crate::RecordLocation {$/;" c
|
||||
LOG_LEVEL_NAMES /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub static LOG_LEVEL_NAMES: [&'static str; 7] =$/;" c
|
||||
LOG_LEVEL_SHORT_NAMES /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub static LOG_LEVEL_SHORT_NAMES: [&'static str; 7] =$/;" c
|
||||
Level /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl Level {$/;" i
|
||||
Level /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub enum Level {$/;" g
|
||||
LevelFilter /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D: Drain> LevelFilter<D> {$/;" i
|
||||
LevelFilter /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct LevelFilter<D: Drain>(pub D, pub Level);$/;" s
|
||||
Logger /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D> Logger<D>$/;" i
|
||||
Logger /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct Logger<D = Arc<SendSyncRefUnwindSafeDrain<Ok = (), Err = Never>>>$/;" s
|
||||
MapErrFn /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub trait MapErrFn<EI, EO>$/;" t
|
||||
MapErrFn /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub trait MapErrFn<EI, EO>: 'static + Sync + Send + Fn(EI) -> EO {}$/;" t
|
||||
MapErrFn for T /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T, EI, EO> MapErrFn<EI, EO> for T$/;" i
|
||||
MapError /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D: Drain, E> MapError<D, E> {$/;" i
|
||||
MapError /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct MapError<D: Drain, E> {$/;" s
|
||||
MultiListNode /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^struct MultiListNode {$/;" s
|
||||
MutexDrainError /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub enum MutexDrainError<D: Drain> {$/;" g
|
||||
Never /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub type Never = private::NeverStruct;$/;" T
|
||||
NeverStruct /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub struct NeverStruct(());$/;" s
|
||||
Ok /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ type Ok = ();$/;" T
|
||||
Ok /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ type Ok = ();$/;" T
|
||||
Ok /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ type Ok = ();$/;" T
|
||||
Ok /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ type Ok = (D1::Ok, D2::Ok);$/;" T
|
||||
Ok /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ type Ok = D::Ok;$/;" T
|
||||
Ok /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ type Ok = Option<D::Ok>;$/;" T
|
||||
Ok /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ type Ok;$/;" T
|
||||
Ok /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^ type Ok = ();$/;" T
|
||||
OwnedKV /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct OwnedKV<T>($/;" s
|
||||
OwnedKVList /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl OwnedKVList {$/;" i
|
||||
OwnedKVList /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct OwnedKVList {$/;" s
|
||||
OwnedKVListNode /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^struct OwnedKVListNode<T>$/;" s
|
||||
OwnedKeyValueList /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub type OwnedKeyValueList = OwnedKVList;$/;" T
|
||||
PlainDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<W> PlainDecorator<W>$/;" i
|
||||
PlainDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub struct PlainDecorator<W>(RefCell<W>)$/;" s
|
||||
PlainRecordDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub struct PlainRecordDecorator<'a, W: 'a>(&'a RefCell<W>)$/;" s
|
||||
PlainSyncDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<W> PlainSyncDecorator<W>$/;" i
|
||||
PlainSyncDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub struct PlainSyncDecorator<W>(sync::Arc<sync::Mutex<W>>)$/;" s
|
||||
PlainSyncRecordDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub struct PlainSyncRecordDecorator<W>$/;" s
|
||||
PushFnSerializer /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub type PushFnSerializer<'a> = PushFnValueSerializer<'a>;$/;" T
|
||||
PushFnValue /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct PushFnValue<F>(pub F)$/;" s
|
||||
PushFnValueSerializer /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<'a> PushFnValueSerializer<'a> {$/;" i
|
||||
PushFnValueSerializer /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct PushFnValueSerializer<'a> {$/;" s
|
||||
PushLazy /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub type PushLazy<T> = PushFnValue<T>;$/;" T
|
||||
RS /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ static RS : $crate::RecordStatic<'static> = record_static!($lvl, $tag);$/;" c
|
||||
RS /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ static RS : $crate::RecordStatic<'static> = slog_record_static!($lvl,$/;" c
|
||||
Record /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<'a> Record<'a> {$/;" i
|
||||
Record /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct Record<'a> {$/;" s
|
||||
RecordDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub trait RecordDecorator: io::Write {$/;" t
|
||||
RecordDecorator for Box /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl RecordDecorator for Box<RecordDecorator> {$/;" i
|
||||
RecordDecorator for PlainRecordDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<'a, W> RecordDecorator for PlainRecordDecorator<'a, W>$/;" i
|
||||
RecordDecorator for PlainSyncRecordDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<W> RecordDecorator for PlainSyncRecordDecorator<W>$/;" i
|
||||
RecordDecorator for TermRecordDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<'a> RecordDecorator for TermRecordDecorator<'a> {$/;" i
|
||||
RecordLocation /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct RecordLocation {$/;" s
|
||||
RecordStatic /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct RecordStatic<'a> {$/;" s
|
||||
Result /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub type Result<T = ()> = result::Result<T, Error>;$/;" T
|
||||
STATIC_TERMINATOR_UNIT /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub static STATIC_TERMINATOR_UNIT: () = ();$/;" c
|
||||
SendRefUnwindSafeDrain /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub trait SendRefUnwindSafeDrain: Drain + Send + RefUnwindSafe {}$/;" t
|
||||
SendRefUnwindSafeDrain /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub trait SendRefUnwindSafeDrain: Drain + Send {}$/;" t
|
||||
SendRefUnwindSafeDrain for T /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T> SendRefUnwindSafeDrain for T$/;" i
|
||||
SendSyncRefUnwindSafeDrain /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub trait SendSyncRefUnwindSafeDrain: Drain + Send + Sync + RefUnwindSafe {}$/;" t
|
||||
SendSyncRefUnwindSafeDrain /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub trait SendSyncRefUnwindSafeDrain: Drain + Send + Sync {}$/;" t
|
||||
SendSyncRefUnwindSafeDrain for T /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T> SendSyncRefUnwindSafeDrain for T$/;" i
|
||||
SendSyncRefUnwindSafeKV /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub trait SendSyncRefUnwindSafeKV: KV + Send + Sync + RefUnwindSafe {}$/;" t
|
||||
SendSyncRefUnwindSafeKV /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub trait SendSyncRefUnwindSafeKV: KV + Send + Sync {}$/;" t
|
||||
SendSyncRefUnwindSafeKV for T /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T> SendSyncRefUnwindSafeKV for T$/;" i
|
||||
SendSyncUnwindSafe /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub trait SendSyncUnwindSafe: Send + Sync + UnwindSafe {}$/;" t
|
||||
SendSyncUnwindSafe for T /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T> SendSyncUnwindSafe for T$/;" i
|
||||
SendSyncUnwindSafeDrain /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub trait SendSyncUnwindSafeDrain: Drain + Send + Sync + UnwindSafe {}$/;" t
|
||||
SendSyncUnwindSafeDrain /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub trait SendSyncUnwindSafeDrain: Drain + Send + Sync {}$/;" t
|
||||
SendSyncUnwindSafeDrain for T /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T> SendSyncUnwindSafeDrain for T$/;" i
|
||||
Serialize /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub type Serialize = Value;$/;" T
|
||||
Serializer /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<'a> Serializer<'a> {$/;" i
|
||||
Serializer /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^struct Serializer<'a> {$/;" s
|
||||
Serializer /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub trait Serializer {$/;" t
|
||||
Serializer for AsFmtSerializer /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<F> Serializer for AsFmtSerializer<F>$/;" i
|
||||
Serializer for ToSendSerializer /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^impl Serializer for ToSendSerializer {$/;" i
|
||||
SingleKV /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub struct SingleKV<V>(pub Key, pub V)$/;" s
|
||||
TIMESTAMP_FORMAT /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^const TIMESTAMP_FORMAT: &'static str = "%b %d %H:%M:%S%.3f";$/;" c
|
||||
TermDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl TermDecorator {$/;" i
|
||||
TermDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub struct TermDecorator {$/;" s
|
||||
TermDecoratorBuilder /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl TermDecoratorBuilder {$/;" i
|
||||
TermDecoratorBuilder /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub struct TermDecoratorBuilder {$/;" s
|
||||
TermRecordDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub struct TermRecordDecorator<'a> {$/;" s
|
||||
TestStdoutWriter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub struct TestStdoutWriter;$/;" s
|
||||
ThreadSafeTimestampFn /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub trait ThreadSafeTimestampFn$/;" t
|
||||
ThreadSafeTimestampFn for F /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<F> ThreadSafeTimestampFn for F$/;" i
|
||||
ToSendSerializer /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^impl ToSendSerializer {$/;" i
|
||||
ToSendSerializer /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^struct ToSendSerializer {$/;" s
|
||||
Value /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ impl Value for $t {$/;" i
|
||||
Value /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl Value for () {$/;" i
|
||||
Value /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<'a, V> Value for &'a V$/;" i
|
||||
Value /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub trait Value {$/;" t
|
||||
Value for Arc /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T> Value for Arc<T>$/;" i
|
||||
Value for Box /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T> Value for Box<T>$/;" i
|
||||
Value for FnValue /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<'a, V: 'a + Value, F> Value for FnValue<V, F>$/;" i
|
||||
Value for Option /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T: Value> Value for Option<T> {$/;" i
|
||||
Value for PushFnValue /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<F> Value for PushFnValue<F>$/;" i
|
||||
Value for Rc /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T> Value for Rc<T>$/;" i
|
||||
Value for String /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl Value for String {$/;" i
|
||||
Value for core /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T> Value for core::num::Wrapping<T>$/;" i
|
||||
Value for fmt /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<'a> Value for fmt::Arguments<'a> {$/;" i
|
||||
Value for std /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<'a> Value for std::path::Display<'a>$/;" i
|
||||
Value for str /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl Value for str {$/;" i
|
||||
ValueSerializer /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub type ValueSerializer<'a> = PushFnValueSerializer<'a>;$/;" T
|
||||
X /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^ struct X {$/;" s
|
||||
__slog_static_max_level /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub fn __slog_static_max_level() -> FilterLevel {$/;" f
|
||||
as_short_str /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn as_short_str(&self) -> &'static str {$/;" f
|
||||
as_str /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn as_str(&self) -> &'static str {$/;" f
|
||||
as_usize /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn as_usize(&self) -> usize {$/;" f
|
||||
b /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! b($/;" d
|
||||
bar /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^ fn bar(&self) -> u32 {$/;" f
|
||||
build /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ pub fn build(self) -> Async {$/;" f
|
||||
build /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ pub fn build(self) -> AsyncCore {$/;" f
|
||||
build /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ pub fn build(self) -> CompactFormat<D> {$/;" f
|
||||
build /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ pub fn build(self) -> FullFormat<D> {$/;" f
|
||||
build /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ pub fn build(self) -> TermDecorator {$/;" f
|
||||
build_no_guard /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ pub fn build_no_guard(self) -> Async {$/;" f
|
||||
build_no_guard /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ pub fn build_no_guard(self) -> AsyncCore {$/;" f
|
||||
build_with_guard /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ pub fn build_with_guard(self) -> (Async, AsyncGuard) {$/;" f
|
||||
build_with_guard /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ pub fn build_with_guard(self) -> (AsyncCore, AsyncGuard) {$/;" f
|
||||
cause /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn cause(&self) -> Option<&std::error::Error> {$/;" f
|
||||
chan_size /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ pub fn chan_size(mut self, s: usize) -> Self {$/;" f
|
||||
chan_size /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ pub fn chan_size(self, s: usize) -> Self {$/;" f
|
||||
column /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn column(&self) -> u32 {$/;" f
|
||||
convert /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<T> convert::From<OwnedKV<T>> for OwnedKVList$/;" i
|
||||
core::fmt::Display for Error /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl core::fmt::Display for Error {$/;" i
|
||||
count /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn count(&self) -> usize {$/;" f
|
||||
crit /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! crit($/;" d
|
||||
cs /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^macro_rules! cs($/;" d
|
||||
custom /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ pub fn custom<$/;" f
|
||||
debug /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! debug($/;" d
|
||||
default /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ pub fn default<$/;" f
|
||||
description /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn description(&self) -> &str {$/;" f
|
||||
drop /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn drop(&mut self) {$/;" f
|
||||
drop /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn drop(&mut self) {$/;" f
|
||||
drop /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn drop(&mut self) {$/;" f
|
||||
emit /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn emit<'b, S: 'b + Value>(mut self, s: S) -> Result {$/;" f
|
||||
emit_arguments /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_arguments($/;" f
|
||||
emit_arguments /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_arguments($/;" f
|
||||
emit_arguments /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn emit_arguments(&mut self, key: Key, val: &fmt::Arguments) -> Result {$/;" f
|
||||
emit_arguments /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn emit_arguments(&mut self, key: Key, val: &fmt::Arguments) -> Result;$/;" f
|
||||
emit_bool /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_bool(&mut self, key: Key, val: bool) -> slog::Result {$/;" f
|
||||
emit_bool /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_bool(&mut self, key: &str, val: bool) -> slog::Result {$/;" f
|
||||
emit_char /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_char(&mut self, key: Key, val: char) -> slog::Result {$/;" f
|
||||
emit_char /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_char(&mut self, key: &str, val: char) -> slog::Result {$/;" f
|
||||
emit_f32 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_f32(&mut self, key: Key, val: f32) -> slog::Result {$/;" f
|
||||
emit_f32 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_f32(&mut self, key: &str, val: f32) -> slog::Result {$/;" f
|
||||
emit_f64 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_f64(&mut self, key: Key, val: f64) -> slog::Result {$/;" f
|
||||
emit_f64 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_f64(&mut self, key: &str, val: f64) -> slog::Result {$/;" f
|
||||
emit_i16 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_i16(&mut self, key: Key, val: i16) -> slog::Result {$/;" f
|
||||
emit_i16 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_i16(&mut self, key: &str, val: i16) -> slog::Result {$/;" f
|
||||
emit_i32 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_i32(&mut self, key: Key, val: i32) -> slog::Result {$/;" f
|
||||
emit_i32 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_i32(&mut self, key: &str, val: i32) -> slog::Result {$/;" f
|
||||
emit_i64 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_i64(&mut self, key: Key, val: i64) -> slog::Result {$/;" f
|
||||
emit_i64 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_i64(&mut self, key: &str, val: i64) -> slog::Result {$/;" f
|
||||
emit_i8 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_i8(&mut self, key: Key, val: i8) -> slog::Result {$/;" f
|
||||
emit_i8 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_i8(&mut self, key: &str, val: i8) -> slog::Result {$/;" f
|
||||
emit_isize /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_isize(&mut self, key: Key, val: isize) -> slog::Result {$/;" f
|
||||
emit_isize /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_isize(&mut self, key: &str, val: isize) -> slog::Result {$/;" f
|
||||
emit_none /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_none(&mut self, key: Key) -> slog::Result {$/;" f
|
||||
emit_none /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_none(&mut self, key: &str) -> slog::Result {$/;" f
|
||||
emit_none /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn emit_none(&mut self, key: Key) -> Result {$/;" f
|
||||
emit_str /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_str(&mut self, key: Key, val: &str) -> slog::Result {$/;" f
|
||||
emit_str /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_str(&mut self, key: &str, val: &str) -> slog::Result {$/;" f
|
||||
emit_u16 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_u16(&mut self, key: Key, val: u16) -> slog::Result {$/;" f
|
||||
emit_u16 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_u16(&mut self, key: &str, val: u16) -> slog::Result {$/;" f
|
||||
emit_u32 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_u32(&mut self, key: Key, val: u32) -> slog::Result {$/;" f
|
||||
emit_u32 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_u32(&mut self, key: &str, val: u32) -> slog::Result {$/;" f
|
||||
emit_u64 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_u64(&mut self, key: Key, val: u64) -> slog::Result {$/;" f
|
||||
emit_u64 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_u64(&mut self, key: &str, val: u64) -> slog::Result {$/;" f
|
||||
emit_u8 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_u8(&mut self, key: Key, val: u8) -> slog::Result {$/;" f
|
||||
emit_u8 /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_u8(&mut self, key: &str, val: u8) -> slog::Result {$/;" f
|
||||
emit_unit /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_unit(&mut self, key: Key) -> slog::Result {$/;" f
|
||||
emit_unit /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_unit(&mut self, key: &str) -> slog::Result {$/;" f
|
||||
emit_unit /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn emit_unit(&mut self, key: Key) -> Result {$/;" f
|
||||
emit_usize /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn emit_usize(&mut self, key: Key, val: usize) -> slog::Result {$/;" f
|
||||
emit_usize /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn emit_usize(&mut self, key: &str, val: usize) -> slog::Result {$/;" f
|
||||
error /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! error($/;" d
|
||||
expressions /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^fn expressions() {$/;" f
|
||||
expressions_fmt /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^fn expressions_fmt() {$/;" f
|
||||
file /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn file(&self) -> &'static str {$/;" f
|
||||
filter /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn filter<F>(self, f: F) -> Filter<Self, F>$/;" f
|
||||
filter_level /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn filter_level(self, level: Level) -> LevelFilter<Self>$/;" f
|
||||
filterlevel_sanity /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^fn filterlevel_sanity() {$/;" f
|
||||
finish /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn finish(self) -> Box<KV + Send> {$/;" f
|
||||
finish /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn finish(&mut self) -> io::Result<usize> {$/;" f
|
||||
finish /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn finish(mut self) -> io::Result<()> {$/;" f
|
||||
flush /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn flush(&mut self) -> io::Result<()> {$/;" f
|
||||
fmt /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {$/;" f
|
||||
fmt /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {$/;" f
|
||||
fmt /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn fmt(&self, fmt: &mut core::fmt::Formatter) -> std::fmt::Result {$/;" f
|
||||
fmt::Debug for Logger /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D> fmt::Debug for Logger<D>$/;" i
|
||||
fmt::Debug for MutexDrainError /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D> fmt::Debug for MutexDrainError<D>$/;" i
|
||||
fmt::Debug for OwnedKVList /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl fmt::Debug for OwnedKVList {$/;" i
|
||||
fmt::Display for Level /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl fmt::Display for Level {$/;" i
|
||||
fmt::Display for MutexDrainError /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D: Drain> fmt::Display for MutexDrainError<D>$/;" i
|
||||
force_color /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ pub fn force_color(mut self) -> Self {$/;" f
|
||||
force_plain /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ pub fn force_plain(mut self) -> Self {$/;" f
|
||||
format_compact /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn format_compact($/;" f
|
||||
format_full /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn format_full($/;" f
|
||||
from /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn from(_: mpsc::TrySendError<T>) -> AsyncError {$/;" f
|
||||
from /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn from(_: std::sync::TryLockError<T>) -> AsyncError {$/;" f
|
||||
from /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn from(err: std::sync::PoisonError<T>) -> AsyncError {$/;" f
|
||||
from /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn from($/;" f
|
||||
from /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn from(_: core::fmt::Error) -> Error {$/;" f
|
||||
from /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn from(e: Error) -> std::io::Error {$/;" f
|
||||
from /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn from(err: std::io::Error) -> Error {$/;" f
|
||||
from /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn from(from: OwnedKV<T>) -> Self {$/;" f
|
||||
from_str /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn from_str(level: &str) -> core::result::Result<FilterLevel, ()> {$/;" f
|
||||
from_str /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn from_str(level: &str) -> core::result::Result<Level, ()> {$/;" f
|
||||
from_usize /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn from_usize(u: usize) -> Option<FilterLevel> {$/;" f
|
||||
from_usize /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn from_usize(u: usize) -> Option<Level> {$/;" f
|
||||
function /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn function(&self) -> &'static str {$/;" f
|
||||
fuse /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn fuse(self) -> Fuse<Self>$/;" f
|
||||
get_sender /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn get_sender($/;" f
|
||||
ignore_res /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn ignore_res(self) -> IgnoreResult<Self>$/;" f
|
||||
impl_default_as_fmt /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! impl_default_as_fmt{$/;" d
|
||||
impl_value_for /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! impl_value_for{$/;" d
|
||||
info /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! info($/;" d
|
||||
into_erased /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn into_erased($/;" f
|
||||
io::Write for CountingWriter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<'a> io::Write for CountingWriter<'a> {$/;" i
|
||||
io::Write for PlainRecordDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<'a, W> io::Write for PlainRecordDecorator<'a, W>$/;" i
|
||||
io::Write for PlainSyncRecordDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<W> io::Write for PlainSyncRecordDecorator<W>$/;" i
|
||||
io::Write for TermRecordDecorator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<'a> io::Write for TermRecordDecorator<'a> {$/;" i
|
||||
io::Write for TestStdoutWriter /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl io::Write for TestStdoutWriter {$/;" i
|
||||
is_at_least /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn is_at_least(&self, level: Self) -> bool {$/;" f
|
||||
kv /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn kv(&self) -> BorrowedKV {$/;" f
|
||||
kv /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! kv($/;" d
|
||||
level /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn level(&self) -> Level {$/;" f
|
||||
level_at_least /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^fn level_at_least() {$/;" f
|
||||
level_from_str /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^fn level_from_str() {$/;" f
|
||||
level_to_color /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ pub fn level_to_color(level: slog::Level) -> u16 {$/;" f
|
||||
line /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn line(&self) -> u32 {$/;" f
|
||||
list /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn list(&self) -> &OwnedKVList {$/;" f
|
||||
location /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn location(&self) -> &RecordLocation {$/;" f
|
||||
log /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn log($/;" f
|
||||
log /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn log($/;" f
|
||||
log /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn log($/;" f
|
||||
log /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn log(&self, _: &Record, _: &OwnedKVList) -> result::Result<(), Never> {$/;" f
|
||||
log /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn log(&self, record: &Record) {$/;" f
|
||||
log /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! log($/;" d
|
||||
log /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^ fn log($/;" f
|
||||
logger_fmt_debug_sanity /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^ fn logger_fmt_debug_sanity() {$/;" f
|
||||
logger_to_erased /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^fn logger_to_erased() {$/;" f
|
||||
makers /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^fn makers() {$/;" f
|
||||
map /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn map<F, R>(self, f: F) -> R$/;" f
|
||||
map_err /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn map_err<F, E>(self, f: F) -> MapError<Self, E>$/;" f
|
||||
max /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn max() -> Self {$/;" f
|
||||
maybe_print_comma /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn maybe_print_comma(&mut self) -> io::Result<()> {$/;" f
|
||||
min /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn min() -> Self {$/;" f
|
||||
module /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn module(&self) -> &'static str {$/;" f
|
||||
msg /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn msg(&self) -> &fmt::Arguments {$/;" f
|
||||
multichain /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^ fn multichain() {$/;" f
|
||||
new /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn new() -> Self {$/;" f
|
||||
new /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn new(drain: D) -> AsyncBuilder<D> {$/;" f
|
||||
new /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn new(drain: D) -> Self {$/;" f
|
||||
new /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ pub fn new<D: slog::Drain<Err = slog::Never, Ok = ()> + Send + 'static>($/;" f
|
||||
new /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ pub fn new<D>(drain: D) -> Self$/;" f
|
||||
new /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn new($/;" f
|
||||
new /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn new() -> Self {$/;" f
|
||||
new /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn new(wrapped: &'a mut io::Write) -> CountingWriter {$/;" f
|
||||
new /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ pub fn new() -> TermDecoratorBuilder {$/;" f
|
||||
new /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ pub fn new(d: D) -> CompactFormatBuilder<D> {$/;" f
|
||||
new /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ pub fn new(d: D) -> FullFormatBuilder<D> {$/;" f
|
||||
new /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ pub fn new(io: W) -> Self {$/;" f
|
||||
new /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn new<T>($/;" f
|
||||
new /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn new($/;" f
|
||||
new /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn new(drain1: D1, drain2: D2) -> Self {$/;" f
|
||||
new /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn new(drain: D) -> Self {$/;" f
|
||||
new /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn new(drain: D, cond: F) -> Self {$/;" f
|
||||
new /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn new(drain: D, level: Level) -> Self {$/;" f
|
||||
new /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn new<F>(drain: D, map_fn: F) -> Self$/;" f
|
||||
new /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn new<T>(&self, values: OwnedKV<T>) -> Logger<D>$/;" f
|
||||
no_imports /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^mod no_imports {$/;" m
|
||||
o /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! o($/;" d
|
||||
print_msg_header /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^fn print_msg_header($/;" f
|
||||
private /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^mod private {$/;" m
|
||||
push_dropped /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn push_dropped(&self, logger_values: &OwnedKVList) -> AsyncResult<()> {$/;" f
|
||||
record /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! record($/;" d
|
||||
record_static /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! record_static($/;" d
|
||||
reset /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn reset(&mut self) -> io::Result<()> {$/;" f
|
||||
reset /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn reset(&mut self) -> io::Result<()>;$/;" f
|
||||
root /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn root<T>(values: OwnedKV<T>) -> Self$/;" f
|
||||
root /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn root<T>(drain: D, values: OwnedKV<T>) -> Logger$/;" f
|
||||
root_typed /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn root_typed<T>(drain: D, values: OwnedKV<T>) -> Logger<D>$/;" f
|
||||
s /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^macro_rules! s($/;" d
|
||||
send /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn send(&self, r: AsyncRecord) -> AsyncResult<()> {$/;" f
|
||||
ser /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^pub mod ser {$/;" m
|
||||
serialize /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn serialize(&self,$/;" f
|
||||
serialize /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn serialize($/;" f
|
||||
serialize /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn serialize(&self, record: &Record, serializer: &mut Serializer)$/;" f
|
||||
serialize /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ fn serialize(&self,$/;" f
|
||||
serialize /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn serialize<'b, S: 'b + Value>(self, s: S) -> Result {$/;" f
|
||||
serialize /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^ fn serialize($/;" f
|
||||
should_use_color /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn should_use_color(&self) -> bool {$/;" f
|
||||
simple_logger_erased /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^fn simple_logger_erased() {$/;" f
|
||||
slog::ser::Serializer for CompactFormatSerializer /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<'a> slog::ser::Serializer for CompactFormatSerializer<'a> {$/;" i
|
||||
slog::ser::Serializer for Serializer /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^impl<'a> slog::ser::Serializer for Serializer<'a> {$/;" i
|
||||
slog_b /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! slog_b($/;" d
|
||||
slog_crit /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! slog_crit($/;" d
|
||||
slog_debug /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! slog_debug($/;" d
|
||||
slog_error /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! slog_error($/;" d
|
||||
slog_info /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! slog_info($/;" d
|
||||
slog_kv /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! slog_kv($/;" d
|
||||
slog_log /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! slog_log($/;" d
|
||||
slog_o /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! slog_o($/;" d
|
||||
slog_record /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! slog_record($/;" d
|
||||
slog_record_static /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! slog_record_static($/;" d
|
||||
slog_trace /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! slog_trace($/;" d
|
||||
slog_warn /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! slog_warn($/;" d
|
||||
spawn_thread /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-async-2.1.0/lib.rs /^ fn spawn_thread($/;" f
|
||||
start_comma /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn start_comma(&mut self) -> io::Result<()> {$/;" f
|
||||
start_key /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn start_key(&mut self) -> io::Result<()> {$/;" f
|
||||
start_level /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn start_level(&mut self) -> io::Result<()> {$/;" f
|
||||
start_msg /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn start_msg(&mut self) -> io::Result<()> {$/;" f
|
||||
start_separator /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn start_separator(&mut self) -> io::Result<()> {$/;" f
|
||||
start_timestamp /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn start_timestamp(&mut self) -> io::Result<()> {$/;" f
|
||||
start_value /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn start_value(&mut self) -> io::Result<()> {$/;" f
|
||||
start_whitespace /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn start_whitespace(&mut self) -> io::Result<()> {$/;" f
|
||||
std::error::Error for Error /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl std::error::Error for Error {$/;" i
|
||||
std::error::Error for MutexDrainError /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^impl<D> std::error::Error for MutexDrainError<D>$/;" i
|
||||
std_only /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^mod std_only {$/;" m
|
||||
stderr /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ pub fn stderr(mut self) -> Self {$/;" f
|
||||
stdout /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ pub fn stdout(mut self) -> Self {$/;" f
|
||||
tag /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn tag(&self) -> &str {$/;" f
|
||||
takes_arced_drain /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^ fn takes_arced_drain(_l: Logger) {}$/;" f
|
||||
term_compact /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub fn term_compact() -> CompactFormat<TermDecorator> {$/;" f
|
||||
term_error_to_io_error /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^fn term_error_to_io_error(e: term::Error) -> io::Error {$/;" f
|
||||
term_full /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub fn term_full() -> FullFormat<TermDecorator> {$/;" f
|
||||
test_o_macro_expansion /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^ fn test_o_macro_expansion() {$/;" f
|
||||
test_slog_o_macro_expansion /home/dpc/lab/rust/slog/slog-rs/src/tests.rs /^ fn test_slog_o_macro_expansion() {$/;" f
|
||||
tests /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^mod tests;$/;" m
|
||||
timestamp_local /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub fn timestamp_local(io: &mut io::Write) -> io::Result<()> {$/;" f
|
||||
timestamp_utc /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^pub fn timestamp_utc(io: &mut io::Write) -> io::Result<()> {$/;" f
|
||||
to_erased /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^ pub fn to_erased($/;" f
|
||||
trace /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! trace($/;" d
|
||||
try_build /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ pub fn try_build(self) -> Option<TermDecorator> {$/;" f
|
||||
use_custom_timestamp /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ pub fn use_custom_timestamp<F>(mut self, f: F) -> Self$/;" f
|
||||
use_local_timestamp /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ pub fn use_local_timestamp(mut self) -> Self {$/;" f
|
||||
use_original_order /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ pub fn use_original_order(mut self) -> Self {$/;" f
|
||||
use_utc_timestamp /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ pub fn use_utc_timestamp(mut self) -> Self {$/;" f
|
||||
warn /home/dpc/lab/rust/slog/slog-rs/src/lib.rs /^macro_rules! warn($/;" d
|
||||
with_record /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn with_record<F>($/;" f
|
||||
write /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {$/;" f
|
||||
write /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn write(&mut self, data: &[u8]) -> io::Result<usize> {$/;" f
|
||||
write_all /home/dpc/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-term-2.2.0/src/lib.rs /^ fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {$/;" f
|
|
@ -1,321 +0,0 @@
|
|||
/// Logging drain
|
||||
///
|
||||
/// Drains generally mean destination for logs, but slog generalize the
|
||||
/// term. `Drain`s are responsible for filtering, modifying, formatting
|
||||
/// and writing the log records into given destination.
|
||||
///
|
||||
/// Implementing this trait allows writing own Drains, that can be combined
|
||||
/// with other drains.
|
||||
pub trait Drain {
|
||||
/// Type of potential errors returned during logging
|
||||
type Error;
|
||||
/// Log one logging record
|
||||
///
|
||||
/// Every logging `Record` built from a logging statement (eg.
|
||||
/// `info!(...)`), and key-value lists of a `Logger` it was executed on
|
||||
/// will be passed to the root drain registered during `Logger::root`.
|
||||
///
|
||||
/// Typically `Drain`s:
|
||||
///
|
||||
/// * pass this information (or not) to the sub-logger(s) (filters)
|
||||
/// * format and write the information the a destination (writers)
|
||||
/// * deal with the errors returned from the sub-logger(s)
|
||||
fn log(&self, info: &Record, &OwnedKeyValueList) -> result::Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
impl<D: Drain+?Sized> Drain for Box<D> {
|
||||
type Error = D::Error;
|
||||
fn log(&self, info: &Record, o: &OwnedKeyValueList) -> result::Result<(), D::Error> {
|
||||
(**self).log(info, o)
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Drain+?Sized> Drain for Arc<D> {
|
||||
type Error = D::Error;
|
||||
fn log(&self, info: &Record, o: &OwnedKeyValueList) -> result::Result<(), D::Error> {
|
||||
(**self).log(info, o)
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience methods for building drains
|
||||
///
|
||||
/// `DrainExt` is implemented for every `Drain` and contains
|
||||
/// convenience methods.
|
||||
pub trait DrainExt: Sized + Drain {
|
||||
/// Map logging errors returned by this drain
|
||||
///
|
||||
/// `f` is a closure that takes `Drain::Error` returned by a given
|
||||
/// drain, and returns new error of potentially different type
|
||||
fn map_err<F, E>(self, f : F) -> MapError<Self, E> where F : 'static + Sync + Send + Fn(<Self as Drain>::Error) -> E {
|
||||
MapError::new(self, f)
|
||||
}
|
||||
|
||||
/// Make `Self` ignore and not report any error
|
||||
fn ignore_err(self) -> IgnoreErr<Self> {
|
||||
IgnoreErr::new(self)
|
||||
}
|
||||
|
||||
/// Make `Self` panic when returning any errors
|
||||
fn fuse(self) -> Fuse<Self> where <Self as Drain>::Error : fmt::Display {
|
||||
Fuse::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<D : Drain> DrainExt for D {}
|
||||
|
||||
/// `Drain` discarding everything
|
||||
///
|
||||
/// `/dev/null` of `Drain`s
|
||||
pub struct Discard;
|
||||
|
||||
impl Drain for Discard {
|
||||
type Error = Never;
|
||||
fn log(&self, _: &Record, _: &OwnedKeyValueList) -> result::Result<(), Never> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// `Drain` filtering records
|
||||
///
|
||||
/// Wraps another `Drain` and passes `Record`s to it, only if they satisfy a
|
||||
/// given condition.
|
||||
pub struct Filter<D: Drain> {
|
||||
drain: D,
|
||||
// eliminated dynamic dispatch, after rust learns `-> impl Trait`
|
||||
cond: Box<Fn(&Record) -> bool + 'static + Send + Sync>,
|
||||
}
|
||||
|
||||
impl<D: Drain> Filter<D> {
|
||||
/// Create `Filter` wrapping given `drain`
|
||||
pub fn new<F: 'static + Sync + Send + Fn(&Record) -> bool>(drain: D, cond: F) -> Self {
|
||||
Filter {
|
||||
drain: drain,
|
||||
cond: Box::new(cond),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Drain> Drain for Filter<D> {
|
||||
type Error = D::Error;
|
||||
fn log(&self,
|
||||
info: &Record,
|
||||
logger_values: &OwnedKeyValueList)
|
||||
-> result::Result<(), Self::Error> {
|
||||
if (self.cond)(&info) {
|
||||
self.drain.log(info, logger_values)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// `Drain` mapping error returned by another `Drain`
|
||||
///
|
||||
/// See `DrainExt::map_err` for convenience function.
|
||||
pub struct MapError<D: Drain, E> {
|
||||
drain: D,
|
||||
// eliminated dynamic dispatch, after rust learns `-> impl Trait`
|
||||
map_fn: Box<Fn(D::Error) -> E + 'static+ Send+Sync>,
|
||||
}
|
||||
|
||||
impl<D: Drain, E> MapError<D, E> {
|
||||
/// Create `Filter` wrapping given `drain`
|
||||
pub fn new<F: 'static + Sync + Send + Fn(<D as Drain>::Error) -> E>(drain: D, map_fn: F) -> Self {
|
||||
MapError {
|
||||
drain: drain,
|
||||
map_fn: Box::new(map_fn),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Drain, E> Drain for MapError<D, E> {
|
||||
type Error = E;
|
||||
fn log(&self,
|
||||
info: &Record,
|
||||
logger_values: &OwnedKeyValueList)
|
||||
-> result::Result<(), Self::Error> {
|
||||
self.drain.log(info, logger_values).map_err(|e| (self.map_fn)(e))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// `Drain` filtering records by `Record` logging level
|
||||
///
|
||||
/// Wraps a drain and passes records to it, only
|
||||
/// if their level is at least given level.
|
||||
///
|
||||
/// TODO: Remove this type. This drain is a special case of `Filter`, but
|
||||
/// because `Filter` can not use static dispatch ATM due to Rust limitations
|
||||
/// that will be lifted in the future, it is a standalone type.
|
||||
pub struct LevelFilter<D: Drain> {
|
||||
level: Level,
|
||||
drain: D,
|
||||
}
|
||||
|
||||
impl<D: Drain> LevelFilter<D> {
|
||||
/// Create `LevelFilter`
|
||||
pub fn new(drain: D, level: Level) -> Self {
|
||||
LevelFilter {
|
||||
level: level,
|
||||
drain: drain,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Drain> Drain for LevelFilter<D> {
|
||||
type Error = D::Error;
|
||||
fn log(&self,
|
||||
info: &Record,
|
||||
logger_values: &OwnedKeyValueList)
|
||||
-> result::Result<(), Self::Error> {
|
||||
if info.level().is_at_least(self.level) {
|
||||
self.drain.log(info, logger_values)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `Drain` duplicating records into two other `Drain`s
|
||||
///
|
||||
/// Can be nested for more than two outputs.
|
||||
pub struct Duplicate<D1: Drain, D2: Drain> {
|
||||
drain1: D1,
|
||||
drain2: D2,
|
||||
}
|
||||
|
||||
|
||||
impl<D1: Drain, D2: Drain> Duplicate<D1, D2> {
|
||||
/// Create `Duplicate`
|
||||
pub fn new(drain1: D1, drain2: D2) -> Self {
|
||||
Duplicate {
|
||||
drain1: drain1,
|
||||
drain2: drain2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Logging error returned by `Duplicate` drain
|
||||
pub enum DuplicateError<E1, E2> {
|
||||
/// First `Drain` has returned error
|
||||
First(E1),
|
||||
/// Second `Drain` has returned error
|
||||
Second(E2),
|
||||
/// Both `Drain`s have returned error
|
||||
Both((E1, E2))
|
||||
}
|
||||
|
||||
impl<E1 : fmt::Display, E2 : fmt::Display> fmt::Display for DuplicateError<E1, E2> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&DuplicateError::First(ref e) => write!(f, "{})", *e),
|
||||
&DuplicateError::Second(ref e) => write!(f, "{})", *e),
|
||||
&DuplicateError::Both((ref e1, ref e2)) => write!(f, "({}, {})", *e1, *e2),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D1 : Drain, D2 : Drain> Drain for Duplicate<D1, D2> {
|
||||
type Error = DuplicateError<D1::Error, D2::Error>;
|
||||
fn log(&self,
|
||||
info: &Record,
|
||||
logger_values: &OwnedKeyValueList)
|
||||
-> result::Result<(), Self::Error> {
|
||||
let res1 = self.drain1.log(info, logger_values);
|
||||
let res2 = self.drain2.log(info, logger_values);
|
||||
|
||||
match (res1, res2) {
|
||||
(Ok(_), Ok(_)) => Ok(()),
|
||||
(Err(e), Ok(_)) => Err(DuplicateError::First(e)),
|
||||
(Ok(_), Err(e)) => Err(DuplicateError::Second(e)),
|
||||
(Err(e1), Err(e2)) => Err(DuplicateError::Both((e1, e2))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// `Drain` panicking on error
|
||||
///
|
||||
/// `Logger` requires a root drain to handle all errors (`Drain::Error == ()`),
|
||||
/// `Fuse` will wrap a `Drain` and panic if it returns any errors.
|
||||
///
|
||||
/// Note: `Drain::Error` must implement `Display`. It's easy to create own
|
||||
/// `Fuse` drain if this requirement can't be fulfilled.
|
||||
pub struct Fuse<D: Drain> {
|
||||
drain: D,
|
||||
}
|
||||
|
||||
impl<D: Drain> Fuse<D> {
|
||||
/// Create `Fuse` wrapping given `drain`
|
||||
pub fn new(drain: D) -> Self {
|
||||
Fuse {
|
||||
drain: drain,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Drain> Drain for Fuse<D> where D::Error : fmt::Display {
|
||||
type Error = Never;
|
||||
fn log(&self,
|
||||
info: &Record,
|
||||
logger_values: &OwnedKeyValueList)
|
||||
-> result::Result<(), Never> {
|
||||
Ok(
|
||||
self.drain.log(info, logger_values).unwrap_or_else(
|
||||
|e| panic!("Fuse: {}", e)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// `Drain` ignoring errors
|
||||
///
|
||||
/// `Logger` requires a root drain to handle all errors (`Drain::Error == ()`),
|
||||
/// `IgnoreErr` will ignore all errors of the drain it wraps.
|
||||
pub struct IgnoreErr<D: Drain> {
|
||||
drain: D,
|
||||
}
|
||||
|
||||
impl<D: Drain> IgnoreErr<D> {
|
||||
/// Create `IgnoreErr` wrapping `drain`
|
||||
pub fn new(drain: D) -> Self {
|
||||
IgnoreErr {
|
||||
drain: drain,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Drain> Drain for IgnoreErr<D> {
|
||||
type Error = Never;
|
||||
fn log(&self,
|
||||
info: &Record,
|
||||
logger_values: &OwnedKeyValueList)
|
||||
-> result::Result<(), Never> {
|
||||
let _ = self.drain.log(info, logger_values);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Filter by `cond` closure
|
||||
pub fn filter<D: Drain, F: 'static + Send + Sync + Fn(&Record) -> bool>(
|
||||
cond: F,
|
||||
d: D
|
||||
) -> Filter<D> {
|
||||
Filter::new(d, cond)
|
||||
}
|
||||
|
||||
/// Filter by log level
|
||||
pub fn level_filter<D: Drain>(level: Level, d: D) -> LevelFilter<D> {
|
||||
LevelFilter::new(d, level)
|
||||
}
|
||||
|
||||
/// Duplicate records to two drains
|
||||
///
|
||||
/// Create `Duplicate` drain.
|
||||
///
|
||||
/// Can be nested for multiple outputs.
|
||||
pub fn duplicate<D1: Drain, D2: Drain>(d1: D1, d2: D2) -> Duplicate<D1, D2> {
|
||||
Duplicate::new(d1, d2)
|
||||
}
|
|
@ -1,222 +0,0 @@
|
|||
/// Official capitalized logging (and logging filtering) level names
|
||||
///
|
||||
/// In order of `as_usize()`.
|
||||
pub static LOG_LEVEL_NAMES: [&'static str; 7] = ["OFF", "CRITICAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"];
|
||||
|
||||
/// Official capitalized logging (and logging filtering) short level names
|
||||
///
|
||||
/// In order of `as_usize()`.
|
||||
pub static LOG_LEVEL_SHORT_NAMES: [&'static str; 7] = ["OFF", "CRIT", "ERRO", "WARN", "INFO", "DEBG", "TRCE"];
|
||||
|
||||
|
||||
/// Logging level associated with a logging `Record`
|
||||
#[repr(usize)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum Level {
|
||||
/// Critical
|
||||
Critical,
|
||||
/// Error
|
||||
Error,
|
||||
/// Warning
|
||||
Warning,
|
||||
/// Info
|
||||
Info,
|
||||
/// Debug
|
||||
Debug,
|
||||
/// Trace
|
||||
Trace
|
||||
}
|
||||
|
||||
/// Logging filtering level
|
||||
#[repr(usize)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum FilterLevel {
|
||||
/// Log nothing
|
||||
Off,
|
||||
/// Log critical level only
|
||||
Critical,
|
||||
/// Log only error level and above
|
||||
Error,
|
||||
/// Log only warning level and above
|
||||
Warning,
|
||||
/// Log only info level and above
|
||||
Info,
|
||||
/// Log only debug level and above
|
||||
Debug,
|
||||
/// Log everything
|
||||
Trace,
|
||||
}
|
||||
|
||||
impl Level {
|
||||
/// Convert to `str` from `LOG_LEVEL_SHORT_NAMES`
|
||||
pub fn as_short_str(&self) -> &'static str {
|
||||
LOG_LEVEL_SHORT_NAMES[self.as_usize()]
|
||||
}
|
||||
|
||||
/// Convert to `str` from `LOG_LEVEL_NAMES`
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
LOG_LEVEL_NAMES[self.as_usize()]
|
||||
}
|
||||
|
||||
/// Cast `Level` to ordering integer
|
||||
///
|
||||
/// `Critical` is the smallest and `Trace` the biggest value
|
||||
#[inline]
|
||||
pub fn as_usize(&self) -> usize {
|
||||
match *self {
|
||||
Level::Critical => 1,
|
||||
Level::Error => 2,
|
||||
Level::Warning => 3,
|
||||
Level::Info => 4,
|
||||
Level::Debug => 5,
|
||||
Level::Trace => 6,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a `Level` from an `usize`
|
||||
///
|
||||
/// This complements `as_usize`
|
||||
#[inline]
|
||||
pub fn from_usize(u: usize) -> Option<Level> {
|
||||
match u {
|
||||
1 => Some(Level::Critical),
|
||||
2 => Some(Level::Error),
|
||||
3 => Some(Level::Warning),
|
||||
4 => Some(Level::Info),
|
||||
5 => Some(Level::Debug),
|
||||
6 => Some(Level::Trace),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FilterLevel {
|
||||
/// Convert to `usize` value
|
||||
///
|
||||
/// `Off` is 0, and `Trace` 6
|
||||
#[inline]
|
||||
pub fn as_usize(&self) -> usize {
|
||||
match *self {
|
||||
FilterLevel::Off => 0,
|
||||
FilterLevel::Critical => 1,
|
||||
FilterLevel::Error => 2,
|
||||
FilterLevel::Warning => 3,
|
||||
FilterLevel::Info => 4,
|
||||
FilterLevel::Debug => 5,
|
||||
FilterLevel::Trace => 6,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a `FilterLevel` from an `usize`
|
||||
///
|
||||
/// This complements `as_usize`
|
||||
#[inline]
|
||||
pub fn from_usize(u: usize) -> Option<FilterLevel> {
|
||||
match u {
|
||||
0 => Some(FilterLevel::Off),
|
||||
1 => Some(FilterLevel::Critical),
|
||||
2 => Some(FilterLevel::Error),
|
||||
3 => Some(FilterLevel::Warning),
|
||||
4 => Some(FilterLevel::Info),
|
||||
5 => Some(FilterLevel::Debug),
|
||||
6 => Some(FilterLevel::Trace),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
/// Maximum logging level (log everything)
|
||||
#[inline]
|
||||
pub fn max() -> Self {
|
||||
FilterLevel::Trace
|
||||
}
|
||||
|
||||
|
||||
/// Minimum logging level (log nothing)
|
||||
#[inline]
|
||||
pub fn min() -> Self {
|
||||
FilterLevel::Off
|
||||
}
|
||||
}
|
||||
|
||||
static ASCII_LOWERCASE_MAP: [u8; 256] = [
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'',
|
||||
b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
|
||||
b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
|
||||
b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
|
||||
b'@',
|
||||
|
||||
b'a', b'b', b'c', b'd', b'e', b'f', b'g',
|
||||
b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o',
|
||||
b'p', b'q', b'r', b's', b't', b'u', b'v', b'w',
|
||||
b'x', b'y', b'z',
|
||||
|
||||
b'[', b'\\', b']', b'^', b'_',
|
||||
b'`', b'a', b'b', b'c', b'd', b'e', b'f', b'g',
|
||||
b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o',
|
||||
b'p', b'q', b'r', b's', b't', b'u', b'v', b'w',
|
||||
b'x', b'y', b'z', b'{', b'|', b'}', b'~', 0x7f,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
|
||||
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
|
||||
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
||||
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
||||
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
|
||||
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
||||
];
|
||||
|
||||
impl FromStr for FilterLevel {
|
||||
type Err = ();
|
||||
fn from_str(level: &str) -> core::result::Result<FilterLevel, ()> {
|
||||
LOG_LEVEL_NAMES.iter()
|
||||
.position(|&name| name.as_bytes().iter().zip(level.as_bytes().iter()).all(|(a, b)| {
|
||||
ASCII_LOWERCASE_MAP[*a as usize] == ASCII_LOWERCASE_MAP[*b as usize]
|
||||
}))
|
||||
.map(|p| FilterLevel::from_usize(p).unwrap()).ok_or(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Level {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.as_short_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Level {
|
||||
/// Returns true if `self` is at least `level` logging level
|
||||
#[inline]
|
||||
pub fn is_at_least(&self, level : Self) -> bool {
|
||||
self.as_usize() <= level.as_usize()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn level_at_least() {
|
||||
assert!(Level::Debug.is_at_least(Level::Debug));
|
||||
assert!(Level::Debug.is_at_least(Level::Trace));
|
||||
assert!(!Level::Debug.is_at_least(Level::Info));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filterlevel_sanity() {
|
||||
assert!(Level::Critical.as_usize() > FilterLevel::Off.as_usize());
|
||||
assert!(Level::Critical.as_usize() == FilterLevel::Critical.as_usize());
|
||||
assert!(Level::Trace.as_usize() == FilterLevel::Trace.as_usize());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn level_from_str() {
|
||||
assert_eq!("info".parse::<FilterLevel>().unwrap(), FilterLevel::Info);
|
||||
}
|
|
@ -1,194 +0,0 @@
|
|||
/// Logging handle used to execute logging statements
|
||||
///
|
||||
/// Logger handles logging context (key-value list) and handles logging
|
||||
/// statements.
|
||||
///
|
||||
/// Child loggers are build from existing loggers, and inherit existing
|
||||
/// key-value pairs from their parents, which can be supplemented with
|
||||
/// new ones.
|
||||
///
|
||||
/// Cloning existing loggers and creating new ones is cheap. Loggers can be
|
||||
/// freely passed around the code.
|
||||
#[derive(Clone)]
|
||||
pub struct Logger {
|
||||
drain: Arc<Drain<Error=Never>+Send+Sync>,
|
||||
values: OwnedKeyValueList,
|
||||
}
|
||||
|
||||
impl Logger {
|
||||
/// Build a root `Logger`
|
||||
///
|
||||
/// All children and their children and so on form one hierarchy
|
||||
/// sharing a common drain.
|
||||
///
|
||||
/// Root logger starts a new hierarchy associated with a given `Drain`. Root
|
||||
/// logger drain must return no errors. See `DrainExt::ignore_err()` and
|
||||
///
|
||||
/// `DrainExt::fuse()`.
|
||||
/// Use `o!` macro to help build key-value pairs with a nicer syntax.
|
||||
///
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate slog;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let _root = slog::Logger::root(
|
||||
/// slog::Discard,
|
||||
/// o!("key1" => "value1", "key2" => "value2"),
|
||||
/// );
|
||||
/// }
|
||||
pub fn root<D: 'static + Drain<Error=Never> + Sized+Send+Sync>(d: D, values: Option<Box<ser::SyncMultiSerialize>>) -> Logger {
|
||||
Logger {
|
||||
drain: Arc::new(d),
|
||||
values: OwnedKeyValueList::root(values),
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a child logger
|
||||
///
|
||||
/// Child logger inherits all existing key-value pairs from it's parent.
|
||||
///
|
||||
/// All children, their children and so on, form one hierarchy sharing
|
||||
/// a common drain.
|
||||
///
|
||||
/// Use `o!` macro to help build key value pairs using nicer syntax.
|
||||
///
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate slog;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let root = slog::Logger::root(slog::Discard,
|
||||
/// o!("key1" => "value1", "key2" => "value2"));
|
||||
/// let _log = root.new(o!("key" => "value"));
|
||||
/// }
|
||||
pub fn new(&self, values: Option<Box<ser::SyncMultiSerialize>>) -> Logger {
|
||||
Logger {
|
||||
drain: self.drain.clone(),
|
||||
values: if let Some(v) = values {
|
||||
OwnedKeyValueList::new(v, self.values.clone())
|
||||
} else {
|
||||
self.values.clone()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Log one logging record
|
||||
///
|
||||
/// Use specific logging functions instead. See `log!` macro
|
||||
/// documentation.
|
||||
#[inline]
|
||||
pub fn log(&self, record: &Record) {
|
||||
let _ = self.drain.log(&record, &self.values);
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Logger {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(f, "Logger("));
|
||||
for (i, (key, _)) in self.values.iter().enumerate() {
|
||||
if i != 0 {
|
||||
try!(write!(f, ", "));
|
||||
}
|
||||
|
||||
try!(write!(f, "{}", key));
|
||||
}
|
||||
try!(write!(f, ")"));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct RecordStatic<'a> {
|
||||
/// Logging level
|
||||
pub level: Level,
|
||||
/// File
|
||||
pub file: &'static str,
|
||||
/// Line
|
||||
pub line: u32,
|
||||
/// Column (currently not implemented)
|
||||
pub column: u32,
|
||||
/// Function (currently not implemented)
|
||||
pub function: &'static str,
|
||||
/// Module
|
||||
pub module: &'static str,
|
||||
/// Target - for backward compatibility with `log`
|
||||
pub target: &'a str,
|
||||
}
|
||||
|
||||
/// One logging record
|
||||
///
|
||||
/// Corresponds to one logging statement like `info!(...)` and carries all it's
|
||||
/// data: eg. message, key-values, key-values of `Logger` used to execute it.
|
||||
///
|
||||
/// Record is passed to `Drain` associated with a given logger hierarchy.
|
||||
pub struct Record<'a> {
|
||||
meta: &'a RecordStatic<'a>,
|
||||
msg: fmt::Arguments<'a>,
|
||||
values: &'a [BorrowedKeyValue<'a>],
|
||||
}
|
||||
|
||||
|
||||
impl<'a> Record<'a> {
|
||||
/// Create a new `Record`
|
||||
#[inline]
|
||||
#[doc(hidden)]
|
||||
pub fn new(
|
||||
s : &'a RecordStatic<'a>,
|
||||
msg: fmt::Arguments<'a>,
|
||||
values: &'a [BorrowedKeyValue<'a>],
|
||||
) -> Self {
|
||||
Record {
|
||||
meta: s,
|
||||
msg: msg,
|
||||
values: values,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a log record message
|
||||
pub fn msg(&self) -> fmt::Arguments {
|
||||
self.msg
|
||||
}
|
||||
|
||||
/// Get record logging level
|
||||
pub fn level(&self) -> Level {
|
||||
self.meta.level
|
||||
}
|
||||
|
||||
/// Get line number
|
||||
pub fn line(&self) -> u32 {
|
||||
self.meta.line
|
||||
}
|
||||
|
||||
/// Get error column
|
||||
pub fn column(&self) -> u32 {
|
||||
self.meta.column
|
||||
}
|
||||
|
||||
/// Get file path
|
||||
pub fn file(&self) -> &'static str {
|
||||
self.meta.file
|
||||
}
|
||||
|
||||
/// Get target
|
||||
///
|
||||
/// Mostly for backward compatibility with `log`
|
||||
pub fn target(&self) -> &str {
|
||||
self.meta.target
|
||||
}
|
||||
|
||||
/// Get module
|
||||
pub fn module(&self) -> &'static str {
|
||||
self.meta.module
|
||||
}
|
||||
|
||||
/// Get function
|
||||
pub fn function(&self) -> &'static str {
|
||||
self.meta.function
|
||||
}
|
||||
|
||||
/// Get Record's key-value pairs
|
||||
pub fn values(&self) -> &'a [BorrowedKeyValue<'a>] {
|
||||
self.values
|
||||
}
|
||||
}
|
|
@ -1,827 +0,0 @@
|
|||
//! # Slog - Structured, extensible, composable logging for Rust
|
||||
//!
|
||||
//! ## Features
|
||||
//!
|
||||
//! * easy to use
|
||||
//! * great performance; see: [slog bench log](https://github.com/dpc/slog-rs/wiki/Bench-log)
|
||||
//! * `#![no_std]` support (with opt-out `std` cargo feature flag)
|
||||
//! * hierarchical loggers
|
||||
//! * lazily evaluated values
|
||||
//! * modular, lightweight and very extensible
|
||||
//! * tiny core crate that does not pull any dependencies
|
||||
//! * feature-crates for specific functionality
|
||||
//! * backward compatibility for standard `log` crate (`slog-stdlog` crate)
|
||||
//! * supports logging-scopes
|
||||
//! * using slog in library does not force users of the library to use slog
|
||||
//! (but gives benefits); see `crates/example-lib`
|
||||
//! * drains & output formatting
|
||||
//! * filtering
|
||||
//! * compile-time log level filter using cargo features (same as in `log` crate)
|
||||
//! * by level, msg, and any other meta-data
|
||||
//! * [`slog-envlogger`](https://github.com/slog-rs/envlogger) - port of `env_logger`
|
||||
//! * multiple outputs
|
||||
//! * asynchronous IO writing
|
||||
//! * terminal output, with color support (`slog-term` crate)
|
||||
//! * Json (`slog-json` crate)
|
||||
//! * Bunyan (`slog-bunyan` crate)
|
||||
//! * syslog (`slog-syslog` crate)
|
||||
//! * first class custom drains
|
||||
//!
|
||||
//! ## Advantages over `log` crate
|
||||
//!
|
||||
//! * **extensible** - `slog` provides core functionality, and some standard
|
||||
//! feature-set. But using traits, anyone can easily implement as
|
||||
//! powerful fully-custom features, publish separately and grow `slog` feature-set
|
||||
//! for everyone.
|
||||
//! * **composable** - Wouldn't it be nice if you could use
|
||||
//! [`env_logger`][env_logger], but output authentication messages to syslog,
|
||||
//! while reporting errors over network in json format? With `slog` drains can
|
||||
//! reuse other drains! You can combine them together, chain, wrap - you name it.
|
||||
//! * **context aware** - It's not just one global logger. Hierarchical
|
||||
//! loggers carry information about context of logging. When logging an error
|
||||
//! condition, you want to know which resource was being handled, on which
|
||||
//! instance of your service, using which source code build, talking with what
|
||||
//! peer, etc. In standard `log` you would have to repeat this information in
|
||||
//! every log statement. In `slog` it will happen automatically. See
|
||||
//! [slog-rs functional overview page][functional-overview] to understand better
|
||||
//! logger and drain hierarchies and log record flow through them.
|
||||
//! * both **human and machine readable** - By keeping the key-value data format,
|
||||
//! meaning of logging data is preserved. Dump your logging to a JSON file, and
|
||||
//! send it to your data-mining system for further analysis. Don't parse it from
|
||||
//! lines of text anymore!
|
||||
//! * **lazy evaluation** and **asynchronous IO** included. Waiting to
|
||||
//! finish writing logging information to disk, or spending time calculating
|
||||
//! data that will be thrown away at the current logging level, are sources of big
|
||||
//! performance waste. Use `AsyncStreamer` drain, and closures to make your logging fast.
|
||||
//! * **run-time configuration** - [`AtomicSwitch`][atomic-switch] drain allows
|
||||
//! changing logging behavior in the running program. You could use eg. signal
|
||||
//! handlers to change logging level or logging destinations. See
|
||||
//! [`signal` example][signal].
|
||||
//!
|
||||
//! [signal]: https://github.com/slog-rs/misc/blob/master/examples/signal.rs
|
||||
//! [env_logger]: https://crates.io/crates/env_logger
|
||||
//! [functional-overview]: https://github.com/slog-rs/slog/wiki/Functional-overview
|
||||
//!
|
||||
//! ## Notable details
|
||||
//!
|
||||
//! `slog` by default removes at compile time trace and debug level statements
|
||||
//! in release builds, and trace level records in debug builds. This makes
|
||||
//! `trace` and `debug` level logging records practically free, which should
|
||||
//! encourage using them freely. If you want to enable trace/debug messages
|
||||
//! or raise the compile time logging level limit, use the following in your
|
||||
//! `Cargo.toml`:
|
||||
//!
|
||||
//! ```norust
|
||||
//! slog = { version = "1.2", features = ["max_level_trace", "release_max_level_warn"] }
|
||||
//! ```
|
||||
//!
|
||||
//! Due to the `macro_rules` limitation log macros syntax comes in several
|
||||
//! versions. See `log!` macro, and pay attention to `;` and `,`
|
||||
//! details.
|
||||
//!
|
||||
//! Root drain (passed to `Logger::root`) must be one that does not ever
|
||||
//! return errors, which forces user to pick error handing strategy. You
|
||||
//! can use `.fuse()` or `.ignore_err()` methods from `DrainExt` to do
|
||||
//! it conveniently.
|
||||
//!
|
||||
//! [signal]: https://github.com/slog-rs/misc/blob/master/examples/signal.rs
|
||||
//! [env_logger]: https://crates.io/crates/env_logger
|
||||
//! [functional-overview]: https://github.com/dpc/slog-rs/wiki/Functional-overview
|
||||
//! [atomic-switch]: https://docs.rs/slog-atomic/0.4.3/slog_atomic/
|
||||
//!
|
||||
//! ## Examples & help
|
||||
//!
|
||||
//! Look at [slog-rs examples in `slog-misc`
|
||||
//! repository](https://github.com/slog-rs/misc/tree/master/examples)
|
||||
//!
|
||||
//! Read [slog-rs wiki pages](https://github.com/slog-rs/slog/wiki)
|
||||
//!
|
||||
//! Check sources of other [software using
|
||||
//! slog-rs](https://crates.io/crates/slog/reverse_dependencies)
|
||||
//!
|
||||
//! Visit [slog-rs gitter channel](https://gitter.im/slog-rs/slog) for immediate help.
|
||||
#![cfg_attr(not(feature = "std"), feature(alloc))]
|
||||
#![cfg_attr(not(feature = "std"), feature(collections))]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
#[cfg(not(feature = "std"))]
|
||||
extern crate alloc;
|
||||
#[cfg(not(feature = "std"))]
|
||||
extern crate collections;
|
||||
|
||||
use core::str::FromStr;
|
||||
use core::fmt;
|
||||
use core::result;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::sync::Arc;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::arc::Arc;
|
||||
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::boxed::Box;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::boxed::Box;
|
||||
|
||||
/// This type is here just to abstract away lack of `!` type support in stable
|
||||
/// rust during time of 1.0 release. It will be switched to `!` at some point
|
||||
/// and `Never` should not be considered "stable" API.
|
||||
#[doc(hidden)]
|
||||
pub type Never = ();
|
||||
|
||||
/// Convenience macro for building `SyncMultiSerialize` trait object
|
||||
///
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate slog;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let drain = slog::Discard;
|
||||
/// let _root = slog::Logger::root(drain, o!("key1" => "value1", "key2" => "value2"));
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(feature = "std")]
|
||||
#[macro_export]
|
||||
macro_rules! o(
|
||||
(@ ; $k:expr => $v:expr) => {
|
||||
o!(@ ($k, $v); )
|
||||
};
|
||||
(@ ; $k:expr => $v:expr, $($args:tt)*) => {
|
||||
o!(@ ($k, $v); $($args)* )
|
||||
};
|
||||
(@ $args_ready:expr; $k:expr => $v:expr) => {
|
||||
o!(@ ($k, $v, $args_ready); )
|
||||
};
|
||||
(@ $args_ready:expr; $k:expr => $v:expr, $($args:tt)* ) => {
|
||||
o!(@ ($k, $v, $args_ready); $($args)* )
|
||||
};
|
||||
(@ $args_ready:expr; ) => {
|
||||
$args_ready
|
||||
};
|
||||
(@ $args_ready:expr;, ) => {
|
||||
$args_ready
|
||||
};
|
||||
() => {
|
||||
None
|
||||
};
|
||||
($($args:tt)+) => {
|
||||
Some(::std::boxed::Box::new(o!(@ ; $($args)+)))
|
||||
};
|
||||
);
|
||||
|
||||
/// Convenience macro for building `SyncMultiSerialize` trait object
|
||||
///
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate slog;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let drain = slog::Discard;
|
||||
/// let _root = slog::Logger::root(drain, o!("key1" => "value1", "key2" => "value2"));
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[macro_export]
|
||||
macro_rules! o(
|
||||
(@ ; $k:expr => $v:expr) => {
|
||||
o!(@ ($k, $v); )
|
||||
};
|
||||
(@ ; $k:expr => $v:expr, $($args:tt)*) => {
|
||||
o!(@ ($k, $v); $($args)* )
|
||||
};
|
||||
(@ $args_ready:expr; $k:expr => $v:expr) => {
|
||||
o!(@ ($k, $v, $args_ready); )
|
||||
};
|
||||
(@ $args_ready:expr; $k:expr => $v:expr, $($args:tt)* ) => {
|
||||
o!(@ ($k, $v, $args_ready); $($args)* )
|
||||
};
|
||||
(@ $args_ready:expr; ) => {
|
||||
$args_ready
|
||||
};
|
||||
(@ $args_ready:expr;, ) => {
|
||||
$args_ready
|
||||
};
|
||||
() => {
|
||||
None
|
||||
};
|
||||
($($args:tt)+) => {
|
||||
Some(::std::boxed::Box::new(o!(@ ; $($args)+)))
|
||||
};
|
||||
);
|
||||
|
||||
/// An alternative, longer-name version of `o` macro
|
||||
///
|
||||
/// Use in case of macro name collisions
|
||||
#[cfg(feature = "std")]
|
||||
#[macro_export]
|
||||
macro_rules! slog_o(
|
||||
(@ ; $k:expr => $v:expr) => {
|
||||
o!(@ ($k, $v); )
|
||||
};
|
||||
(@ ; $k:expr => $v:expr, $($args:tt)*) => {
|
||||
o!(@ ($k, $v); $($args)* )
|
||||
};
|
||||
(@ $args_ready:expr; $k:expr => $v:expr) => {
|
||||
o!(@ ($k, $v, $args_ready); )
|
||||
};
|
||||
(@ $args_ready:expr; $k:expr => $v:expr, $($args:tt)* ) => {
|
||||
o!(@ ($k, $v, $args_ready); $($args)* )
|
||||
};
|
||||
(@ $args_ready:expr; ) => {
|
||||
$args_ready
|
||||
};
|
||||
(@ $args_ready:expr;, ) => {
|
||||
$args_ready
|
||||
};
|
||||
() => {
|
||||
None
|
||||
};
|
||||
($($args:tt)+) => {
|
||||
Some(::std::boxed::Box::new(o!(@ ; $($args)+)))
|
||||
};
|
||||
);
|
||||
|
||||
/// An alternative, longer-name version of `o` macro
|
||||
///
|
||||
/// Use in case of macro name collisions
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[macro_export]
|
||||
macro_rules! slog_o(
|
||||
(@ ; $k:expr => $v:expr) => {
|
||||
o!(@ ($k, $v); )
|
||||
};
|
||||
(@ ; $k:expr => $v:expr, $($args:tt)*) => {
|
||||
o!(@ ($k, $v); $($args)* )
|
||||
};
|
||||
(@ $args_ready:expr; $k:expr => $v:expr) => {
|
||||
o!(@ ($k, $v, $args_ready); )
|
||||
};
|
||||
(@ $args_ready:expr; $k:expr => $v:expr, $($args:tt)* ) => {
|
||||
o!(@ ($k, $v, $args_ready); $($args)* )
|
||||
};
|
||||
(@ $args_ready:expr; ) => {
|
||||
$args_ready
|
||||
};
|
||||
(@ $args_ready:expr;, ) => {
|
||||
$args_ready
|
||||
};
|
||||
() => {
|
||||
None
|
||||
};
|
||||
($($args:tt)+) => {
|
||||
Some(::std::boxed::Box::new(o!(@ ; $($args)+)))
|
||||
};
|
||||
);
|
||||
|
||||
|
||||
/// Log message of a given level
|
||||
///
|
||||
/// Use wrappers `error!`, `warn!` etc. instead
|
||||
///
|
||||
/// The `max_level_*` features can be used to statically disable logging at
|
||||
/// various levels.
|
||||
///
|
||||
/// Use longer name version macros if you want to prevent clash with legacy `log`
|
||||
/// crate macro names (see `examples/alternative_names.rs`).
|
||||
///
|
||||
/// The following invocations are supported.
|
||||
///
|
||||
/// Simple:
|
||||
///
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate slog;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let drain = slog::Discard;
|
||||
/// let root = slog::Logger::root(drain, o!("key1" => "value1", "key2" => "value2"));
|
||||
/// info!(root, "test info log"; "log-key" => true);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Note that `"key" => value` part is optional.
|
||||
///
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate slog;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let drain = slog::Discard;
|
||||
/// let root = slog::Logger::root(drain, o!("key1" => "value1", "key2" => "value2"));
|
||||
/// info!(root, "test info log");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Formatting support:
|
||||
///
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate slog;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let drain = slog::Discard;
|
||||
/// let root = slog::Logger::root(drain, o!("key1" => "value1", "key2" => "value2"));
|
||||
/// info!(root, "log-key" => true; "formatted: {}", 1);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Again, `"key" => value` is optional.
|
||||
///
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate slog;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let drain = slog::Discard;
|
||||
/// let root = slog::Logger::root(drain, o!("key1" => "value1", "key2" => "value2"));
|
||||
/// info!(root, "formatted: {}", 1);
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! log(
|
||||
($lvl:expr, $l:expr, $($k:expr => $v:expr),+; $($args:tt)+ ) => {
|
||||
if $lvl.as_usize() <= $crate::__slog_static_max_level().as_usize() {
|
||||
// prevent generating big `Record` over and over
|
||||
static RS : $crate::RecordStatic<'static> = $crate::RecordStatic {
|
||||
level: $lvl,
|
||||
file: file!(),
|
||||
line: line!(),
|
||||
column: column!(),
|
||||
function: "",
|
||||
module: module_path!(),
|
||||
target: module_path!(),
|
||||
};
|
||||
$l.log(&$crate::Record::new(&RS, format_args!($($args)+), &[$(($k, &$v)),+]))
|
||||
}
|
||||
};
|
||||
($lvl:expr, $l:expr, $msg:expr) => {
|
||||
if $lvl.as_usize() <= $crate::__slog_static_max_level().as_usize() {
|
||||
// prevent generating big `Record` over and over
|
||||
static RS : $crate::RecordStatic<'static> = $crate::RecordStatic {
|
||||
level: $lvl,
|
||||
file: file!(),
|
||||
line: line!(),
|
||||
column: column!(),
|
||||
function: "",
|
||||
module: module_path!(),
|
||||
target: module_path!(),
|
||||
};
|
||||
$l.log(&$crate::Record::new(&RS, format_args!("{}", $msg), &[]))
|
||||
}
|
||||
};
|
||||
($lvl:expr, $l:expr, $msg:expr; $($k:expr => $v:expr),+) => {
|
||||
if $lvl.as_usize() <= $crate::__slog_static_max_level().as_usize() {
|
||||
// prevent generating big `Record` over and over
|
||||
static RS : $crate::RecordStatic<'static> = $crate::RecordStatic {
|
||||
level: $lvl,
|
||||
file: file!(),
|
||||
line: line!(),
|
||||
column: column!(),
|
||||
function: "",
|
||||
module: module_path!(),
|
||||
target: module_path!(),
|
||||
};
|
||||
$l.log(&$crate::Record::new(&RS, format_args!("{}", $msg), &[$(($k, &$v)),+]))
|
||||
}
|
||||
};
|
||||
($lvl:expr, $l:expr, $msg:expr; $($k:expr => $v:expr),+,) => {
|
||||
log!($lvl, $l, $msg; $($k => $v),+)
|
||||
};
|
||||
($lvl:expr, $l:expr, $($args:tt)+) => {
|
||||
if $lvl.as_usize() <= $crate::__slog_static_max_level().as_usize() {
|
||||
// prevent generating big `Record` over and over
|
||||
static RS : $crate::RecordStatic<'static> = $crate::RecordStatic {
|
||||
level: $lvl,
|
||||
file: file!(),
|
||||
line: line!(),
|
||||
column: column!(),
|
||||
function: "",
|
||||
module: module_path!(),
|
||||
target: module_path!(),
|
||||
};
|
||||
$l.log(&$crate::Record::new(&RS, format_args!($($args)+), &[]))
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
/// Log message of a given level (alias)
|
||||
///
|
||||
/// Prefer shorter version, unless it clashes with
|
||||
/// existing `log` crate macro.
|
||||
///
|
||||
/// See `log` for format documentation.
|
||||
///
|
||||
/// ```
|
||||
/// #[macro_use(o,slog_log,slog_info)]
|
||||
/// extern crate slog;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let log = slog::Logger::root(slog::Discard, o!());
|
||||
///
|
||||
/// slog_info!(log, "some interesting info"; "where" => "right here");
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! slog_log(
|
||||
($lvl:expr, $l:expr, $($k:expr => $v:expr),+; $($args:tt)+ ) => {
|
||||
if $lvl.as_usize() <= $crate::__slog_static_max_level().as_usize() {
|
||||
// prevent generating big `Record` over and over
|
||||
static RS : $crate::RecordStatic<'static> = $crate::RecordStatic {
|
||||
level: $lvl,
|
||||
file: file!(),
|
||||
line: line!(),
|
||||
column: column!(),
|
||||
function: "",
|
||||
module: module_path!(),
|
||||
target: module_path!(),
|
||||
};
|
||||
$l.log(&$crate::Record::new(&RS, format_args!($($args)+), &[$(($k, &$v)),+]))
|
||||
}
|
||||
};
|
||||
($lvl:expr, $l:expr, $msg:expr) => {
|
||||
if $lvl.as_usize() <= $crate::__slog_static_max_level().as_usize() {
|
||||
// prevent generating big `Record` over and over
|
||||
static RS : $crate::RecordStatic<'static> = $crate::RecordStatic {
|
||||
level: $lvl,
|
||||
file: file!(),
|
||||
line: line!(),
|
||||
column: column!(),
|
||||
function: "",
|
||||
module: module_path!(),
|
||||
target: module_path!(),
|
||||
};
|
||||
$l.log(&$crate::Record::new(&RS, format_args!("{}", $msg), &[]))
|
||||
}
|
||||
};
|
||||
($lvl:expr, $l:expr, $msg:expr; $($k:expr => $v:expr),+) => {
|
||||
if $lvl.as_usize() <= $crate::__slog_static_max_level().as_usize() {
|
||||
// prevent generating big `Record` over and over
|
||||
static RS : $crate::RecordStatic<'static> = $crate::RecordStatic {
|
||||
level: $lvl,
|
||||
file: file!(),
|
||||
line: line!(),
|
||||
column: column!(),
|
||||
function: "",
|
||||
module: module_path!(),
|
||||
target: module_path!(),
|
||||
};
|
||||
$l.log(&$crate::Record::new(&RS, format_args!("{}", $msg), &[$(($k, &$v)),+]))
|
||||
}
|
||||
};
|
||||
($lvl:expr, $l:expr, $msg:expr; $($k:expr => $v:expr),+,) => {
|
||||
log!($lvl, $l, $msg; $($k => $v),+)
|
||||
};
|
||||
($lvl:expr, $l:expr, $($args:tt)+) => {
|
||||
if $lvl.as_usize() <= $crate::__slog_static_max_level().as_usize() {
|
||||
// prevent generating big `Record` over and over
|
||||
static RS : $crate::RecordStatic<'static> = $crate::RecordStatic {
|
||||
level: $lvl,
|
||||
file: file!(),
|
||||
line: line!(),
|
||||
column: column!(),
|
||||
function: "",
|
||||
module: module_path!(),
|
||||
target: module_path!(),
|
||||
};
|
||||
$l.log(&$crate::Record::new(&RS, format_args!($($args)+), &[]))
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
/// Log critical level record
|
||||
///
|
||||
/// See `log` for documentation.
|
||||
#[macro_export]
|
||||
macro_rules! crit(
|
||||
($($args:tt)+) => {
|
||||
log!($crate::Level::Critical, $($args)+)
|
||||
};
|
||||
);
|
||||
|
||||
/// Log critical level record (alias)
|
||||
///
|
||||
/// Prefer shorter version, unless it clashes with
|
||||
/// existing `log` crate macro.
|
||||
///
|
||||
/// See `slog_log` for documentation.
|
||||
#[macro_export]
|
||||
macro_rules! slog_crit(
|
||||
($($args:tt)+) => {
|
||||
slog_log!($crate::Level::Critical, $($args)+)
|
||||
};
|
||||
);
|
||||
|
||||
/// Log error level record
|
||||
///
|
||||
/// See `log` for documentation.
|
||||
#[macro_export]
|
||||
macro_rules! error(
|
||||
($($args:tt)+) => {
|
||||
log!($crate::Level::Error, $($args)+)
|
||||
};
|
||||
);
|
||||
|
||||
/// Log error level record
|
||||
///
|
||||
/// Prefer shorter version, unless it clashes with
|
||||
/// existing `log` crate macro.
|
||||
///
|
||||
/// See `slog_log` for documentation.
|
||||
#[macro_export]
|
||||
macro_rules! slog_error(
|
||||
($($args:tt)+) => {
|
||||
slog_log!($crate::Level::Error, $($args)+)
|
||||
};
|
||||
);
|
||||
|
||||
|
||||
/// Log warning level record
|
||||
///
|
||||
/// See `log` for documentation.
|
||||
#[macro_export]
|
||||
macro_rules! warn(
|
||||
($($args:tt)+) => {
|
||||
log!($crate::Level::Warning, $($args)+)
|
||||
};
|
||||
);
|
||||
|
||||
/// Log warning level record (alias)
|
||||
///
|
||||
/// Prefer shorter version, unless it clashes with
|
||||
/// existing `log` crate macro.
|
||||
///
|
||||
/// See `slog_log` for documentation.
|
||||
#[macro_export]
|
||||
macro_rules! slog_warn(
|
||||
($($args:tt)+) => {
|
||||
slog_log!($crate::Level::Warning, $($args)+)
|
||||
};
|
||||
);
|
||||
|
||||
/// Log info level record
|
||||
///
|
||||
/// See `slog_log` for documentation.
|
||||
#[macro_export]
|
||||
macro_rules! info(
|
||||
($($args:tt)+) => {
|
||||
log!($crate::Level::Info, $($args)+)
|
||||
};
|
||||
);
|
||||
|
||||
/// Log info level record (alias)
|
||||
///
|
||||
/// Prefer shorter version, unless it clashes with
|
||||
/// existing `log` crate macro.
|
||||
///
|
||||
/// See `slog_log` for documentation.
|
||||
#[macro_export]
|
||||
macro_rules! slog_info(
|
||||
($($args:tt)+) => {
|
||||
slog_log!($crate::Level::Info, $($args)+)
|
||||
};
|
||||
);
|
||||
|
||||
/// Log debug level record
|
||||
///
|
||||
/// See `log` for documentation.
|
||||
#[macro_export]
|
||||
macro_rules! debug(
|
||||
($($args:tt)+) => {
|
||||
log!($crate::Level::Debug, $($args)+)
|
||||
};
|
||||
);
|
||||
|
||||
/// Log debug level record (alias)
|
||||
///
|
||||
/// Prefer shorter version, unless it clashes with
|
||||
/// existing `log` crate macro.
|
||||
///
|
||||
/// See `slog_log` for documentation.
|
||||
#[macro_export]
|
||||
macro_rules! slog_debug(
|
||||
($($args:tt)+) => {
|
||||
slog_log!($crate::Level::Debug, $($args)+)
|
||||
};
|
||||
);
|
||||
|
||||
|
||||
/// Log trace level record
|
||||
///
|
||||
/// See `log` for documentation.
|
||||
#[macro_export]
|
||||
macro_rules! trace(
|
||||
($($args:tt)+) => {
|
||||
log!($crate::Level::Trace, $($args)+)
|
||||
};
|
||||
);
|
||||
|
||||
/// Log trace level record (alias)
|
||||
///
|
||||
/// Prefer shorter version, unless it clashes with
|
||||
/// existing `log` crate macro.
|
||||
///
|
||||
/// See `slog_log` for documentation.
|
||||
#[macro_export]
|
||||
macro_rules! slog_trace(
|
||||
($($args:tt)+) => {
|
||||
slog_log!($crate::Level::Trace, $($args)+)
|
||||
};
|
||||
);
|
||||
|
||||
/// Serialization
|
||||
pub mod ser;
|
||||
|
||||
pub use ser::{PushLazy, ValueSerializer, Serializer, Serialize};
|
||||
|
||||
include!("_level.rs");
|
||||
include!("_logger.rs");
|
||||
include!("_drain.rs");
|
||||
|
||||
/// Key value pair that can be part of a logging record
|
||||
pub type BorrowedKeyValue<'a> = (&'static str, &'a ser::Serialize);
|
||||
|
||||
/// Key value pair that can be owned by `Logger`
|
||||
///
|
||||
/// See `o!(...)` macro.
|
||||
pub type OwnedKeyValue<'a> = (&'static str, &'a ser::SyncSerialize);
|
||||
|
||||
struct OwnedKeyValueListInner {
|
||||
parent: Option<OwnedKeyValueList>,
|
||||
values: Option<Box<ser::SyncMultiSerialize>>,
|
||||
}
|
||||
|
||||
/// Chain of `SyncMultiSerialize`-s of a `Logger` and its ancestors
|
||||
#[derive(Clone)]
|
||||
pub struct OwnedKeyValueList {
|
||||
inner : Arc<OwnedKeyValueListInner>,
|
||||
}
|
||||
|
||||
impl OwnedKeyValueList {
|
||||
/// New `OwnedKeyValueList` node with an existing parent
|
||||
#[deprecated]
|
||||
pub fn new(values: Box<ser::SyncMultiSerialize>, parent: OwnedKeyValueList) -> Self {
|
||||
OwnedKeyValueList {
|
||||
inner: Arc::new(OwnedKeyValueListInner {
|
||||
parent: Some(parent),
|
||||
values: Some(values),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// New `OwnedKeyValue` node without a parent (root)
|
||||
#[deprecated]
|
||||
pub fn root(values: Option<Box<ser::SyncMultiSerialize>>) -> Self {
|
||||
OwnedKeyValueList {
|
||||
inner: Arc::new(OwnedKeyValueListInner {
|
||||
parent: None,
|
||||
values: values,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the parent node element on the chain of values
|
||||
///
|
||||
/// Since `OwnedKeyValueList` is just a chain of `SyncMultiSerialize` instances: each
|
||||
/// containing one more more `OwnedKeyValue`, it's possible to iterate through the whole list
|
||||
/// group-by-group with `parent()` and `values()`.
|
||||
#[deprecated(note="&Option<...> is a stupid type to return. Use `get_parent` for now.")]
|
||||
pub fn parent(&self) -> &Option<OwnedKeyValueList> {
|
||||
&self.inner.parent
|
||||
}
|
||||
|
||||
/// Get the previous element on the chain of values
|
||||
///
|
||||
/// Since `OwnedKeyValueList` is just a chain of `SyncMultiSerialize` instances: each
|
||||
/// containing one more more `OwnedKeyValue`, it's possible to iterate through the whole list
|
||||
/// group-by-group with `parent()` and `values()`.
|
||||
#[deprecated]
|
||||
pub fn previous(&self) -> Option<OwnedKeyValueList> {
|
||||
self.inner.parent.clone()
|
||||
}
|
||||
|
||||
/// Get the head node `SyncMultiSerialize` values
|
||||
pub fn values(&self) -> Option<&ser::SyncMultiSerialize> {
|
||||
self.inner.values.as_ref().map(|b| &**b)
|
||||
}
|
||||
|
||||
/// Iterator over all `OwnedKeyValue`-s in every `SyncMultiSerialize` of the list
|
||||
///
|
||||
/// The order is reverse to how it was built. Eg.
|
||||
///
|
||||
/// ```
|
||||
/// #[macro_use]
|
||||
/// extern crate slog;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let drain = slog::Discard;
|
||||
/// let root = slog::Logger::root(drain, o!("k1" => "v1", "k2" => "k2"));
|
||||
/// let _log = root.new(o!("k3" => "v3", "k4" => "v4"));
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Will produce `OwnedKeyValueList.iter()` that returns `k4, k3, k2, k1`.
|
||||
pub fn iter(&self) -> OwnedKeyValueListIterator {
|
||||
OwnedKeyValueListIterator::new(self)
|
||||
}
|
||||
|
||||
/// Get a unique stable identifier for this node
|
||||
///
|
||||
/// This function is buggy and will be removed at some point.
|
||||
/// Please see https://github.com/slog-rs/slog/issues/90
|
||||
#[deprecated]
|
||||
pub fn id(&self) -> usize {
|
||||
&*self.inner as *const _ as usize
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator over `OwnedKeyValue`-s
|
||||
pub struct OwnedKeyValueListIterator<'a> {
|
||||
next_node: Option<&'a OwnedKeyValueList>,
|
||||
cur: Option<&'a ser::SyncMultiSerialize>,
|
||||
}
|
||||
|
||||
impl<'a> OwnedKeyValueListIterator<'a> {
|
||||
fn new(node: &'a OwnedKeyValueList) -> Self {
|
||||
OwnedKeyValueListIterator {
|
||||
next_node: Some(node),
|
||||
cur: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for OwnedKeyValueListIterator<'a> {
|
||||
type Item = OwnedKeyValue<'a>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
let cur = self.cur;
|
||||
match cur {
|
||||
Some(x) => {
|
||||
let tail = x.tail();
|
||||
self.cur = tail;
|
||||
return Some(x.head())
|
||||
},
|
||||
None => {
|
||||
self.next_node = match self.next_node {
|
||||
Some(ref node) => {
|
||||
self.cur = node.inner.values.as_ref().map(|v| &**v);
|
||||
node.inner.parent.as_ref()
|
||||
}
|
||||
None => return None,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unknown_lints)]
|
||||
#[allow(inline_always)]
|
||||
#[inline(always)]
|
||||
#[doc(hidden)]
|
||||
/// Not an API
|
||||
pub fn __slog_static_max_level() -> FilterLevel {
|
||||
if !cfg!(debug_assertions) {
|
||||
if cfg!(feature = "release_max_level_off") {
|
||||
return FilterLevel::Off;
|
||||
} else if cfg!(feature = "release_max_level_error") {
|
||||
return FilterLevel::Error;
|
||||
} else if cfg!(feature = "release_max_level_warn") {
|
||||
return FilterLevel::Warning;
|
||||
} else if cfg!(feature = "release_max_level_info") {
|
||||
return FilterLevel::Info;
|
||||
} else if cfg!(feature = "release_max_level_debug") {
|
||||
return FilterLevel::Debug;
|
||||
} else if cfg!(feature = "release_max_level_trace") {
|
||||
return FilterLevel::Trace;
|
||||
}
|
||||
}
|
||||
if cfg!(feature = "max_level_off") {
|
||||
FilterLevel::Off
|
||||
} else if cfg!(feature = "max_level_error") {
|
||||
FilterLevel::Error
|
||||
} else if cfg!(feature = "max_level_warn") {
|
||||
FilterLevel::Warning
|
||||
} else if cfg!(feature = "max_level_info") {
|
||||
FilterLevel::Info
|
||||
} else if cfg!(feature = "max_level_debug") {
|
||||
FilterLevel::Debug
|
||||
} else if cfg!(feature = "max_level_trace") {
|
||||
FilterLevel::Trace
|
||||
} else {
|
||||
if !cfg!(debug_assertions) {
|
||||
FilterLevel::Info
|
||||
} else {
|
||||
FilterLevel::Debug
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
|
@ -1,383 +0,0 @@
|
|||
|
||||
#[cfg(feature = "std")]
|
||||
use std;
|
||||
use core;
|
||||
use core::{result, fmt};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::sync::Arc;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::arc::Arc;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::rc::Rc;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::rc::Rc;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::boxed::Box;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::boxed::Box;
|
||||
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::string::String;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use collections::string::String;
|
||||
|
||||
use super::Record;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg(feature = "std")]
|
||||
/// Serialization Error
|
||||
pub enum Error {
|
||||
/// `io::Error`
|
||||
Io(std::io::Error),
|
||||
/// Other error
|
||||
Other
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg(not(feature = "std"))]
|
||||
/// Serialization Error
|
||||
pub enum Error {
|
||||
/// Other error
|
||||
Other
|
||||
}
|
||||
|
||||
/// Serialization `Result`
|
||||
pub type Result = result::Result<(), Error>;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<std::io::Error> for Error {
|
||||
fn from(err: std::io::Error) -> Error {
|
||||
Error::Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<core::fmt::Error> for Error {
|
||||
fn from(_ : core::fmt::Error) -> Error {
|
||||
Error::Other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<Error> for std::io::Error {
|
||||
fn from(e : Error) -> std::io::Error {
|
||||
match e {
|
||||
Error::Io(e) => e,
|
||||
Error::Other => std::io::Error::new(std::io::ErrorKind::Other, "other error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
Error::Io(ref e) => e.description(),
|
||||
Error::Other => "serialization error"
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&std::error::Error> {
|
||||
match *self {
|
||||
Error::Io(ref e) => Some(e),
|
||||
Error::Other => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl core::fmt::Display for Error {
|
||||
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> std::fmt::Result {
|
||||
match *self {
|
||||
Error::Io(ref e) => e.fmt(fmt),
|
||||
Error::Other => fmt.write_str("Other serialization error")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Value that can be serialized
|
||||
///
|
||||
/// Loggers require values in key-value pairs to
|
||||
/// implement this trait.
|
||||
///
|
||||
pub trait Serialize {
|
||||
/// Serialize self into `Serializer`
|
||||
///
|
||||
/// Structs implementing this trait should generally
|
||||
/// only call respective methods of `serializer`.
|
||||
fn serialize(&self, record: &Record, key: &'static str, serializer: &mut Serializer) -> result::Result<(), Error>;
|
||||
}
|
||||
|
||||
/// Value that can be serialized and stored
|
||||
/// in `Logger` itself.
|
||||
///
|
||||
/// As Loggers itself must be thread-safe, they can only
|
||||
/// store values implementing this trait.
|
||||
pub trait SyncSerialize: Send + Sync + 'static + Serialize {}
|
||||
|
||||
|
||||
/// Multiple key-values pairs that can be serialized
|
||||
pub trait SyncMultiSerialize : Send + Sync + 'static {
|
||||
/// Key and value of the first key-value pair
|
||||
fn head(&self) -> (&'static str, &SyncSerialize);
|
||||
/// Next key-value pair (and all following ones)
|
||||
fn tail(&self) -> Option<&SyncMultiSerialize>;
|
||||
}
|
||||
|
||||
/// Serializer
|
||||
///
|
||||
/// Drains using `Format` will internally use
|
||||
/// types implementing this trait.
|
||||
pub trait Serializer {
|
||||
/// Emit bool
|
||||
fn emit_bool(&mut self, key: &'static str, val: bool) -> Result;
|
||||
/// Emit `()`
|
||||
fn emit_unit(&mut self, key: &'static str) -> Result;
|
||||
/// Emit `None`
|
||||
fn emit_none(&mut self, key: &'static str) -> Result;
|
||||
/// Emit char
|
||||
fn emit_char(&mut self, key: &'static str, val: char) -> Result;
|
||||
/// Emit u8
|
||||
fn emit_u8(&mut self, key: &'static str, val: u8) -> Result;
|
||||
/// Emit i8
|
||||
fn emit_i8(&mut self, key: &'static str, val: i8) -> Result;
|
||||
/// Emit u16
|
||||
fn emit_u16(&mut self, key: &'static str, val: u16) -> Result;
|
||||
/// Emit i16
|
||||
fn emit_i16(&mut self, key: &'static str, val: i16) -> Result;
|
||||
/// Emit u32
|
||||
fn emit_u32(&mut self, key: &'static str, val: u32) -> Result;
|
||||
/// Emit i32
|
||||
fn emit_i32(&mut self, key: &'static str, val: i32) -> Result;
|
||||
/// Emit f32
|
||||
fn emit_f32(&mut self, key: &'static str, val: f32) -> Result;
|
||||
/// Emit u64
|
||||
fn emit_u64(&mut self, key: &'static str, val: u64) -> Result;
|
||||
/// Emit i64
|
||||
fn emit_i64(&mut self, key: &'static str, val: i64) -> Result;
|
||||
/// Emit f64
|
||||
fn emit_f64(&mut self, key: &'static str, val: f64) -> Result;
|
||||
/// Emit usize
|
||||
fn emit_usize(&mut self, key: &'static str, val: usize) -> Result;
|
||||
/// Emit isize
|
||||
fn emit_isize(&mut self, key: &'static str, val: isize) -> Result;
|
||||
/// Emit str
|
||||
fn emit_str(&mut self, key: &'static str, val: &str) -> Result;
|
||||
/// Emit `fmt::Arguments`
|
||||
fn emit_arguments(&mut self, key: &'static str, val: &fmt::Arguments) -> Result;
|
||||
}
|
||||
|
||||
macro_rules! impl_serialize_for{
|
||||
($t:ty, $f:ident) => {
|
||||
impl Serialize for $t {
|
||||
fn serialize(&self, _record : &Record, key : &'static str, serializer : &mut Serializer)
|
||||
-> result::Result<(), Error> {
|
||||
serializer.$f(key, *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl SyncSerialize for $t where $t : Send+Sync+'static { }
|
||||
};
|
||||
}
|
||||
|
||||
impl_serialize_for!(usize, emit_usize);
|
||||
impl_serialize_for!(isize, emit_isize);
|
||||
impl_serialize_for!(bool, emit_bool);
|
||||
impl_serialize_for!(char, emit_char);
|
||||
impl_serialize_for!(u8, emit_u8);
|
||||
impl_serialize_for!(i8, emit_i8);
|
||||
impl_serialize_for!(u16, emit_u16);
|
||||
impl_serialize_for!(i16, emit_i16);
|
||||
impl_serialize_for!(u32, emit_u32);
|
||||
impl_serialize_for!(i32, emit_i32);
|
||||
impl_serialize_for!(f32, emit_f32);
|
||||
impl_serialize_for!(u64, emit_u64);
|
||||
impl_serialize_for!(i64, emit_i64);
|
||||
impl_serialize_for!(f64, emit_f64);
|
||||
|
||||
impl Serialize for () {
|
||||
fn serialize(&self, _record: &Record, key: &'static str, serializer: &mut Serializer) -> result::Result<(), Error> {
|
||||
serializer.emit_unit(key)
|
||||
}
|
||||
}
|
||||
|
||||
impl SyncSerialize for () {}
|
||||
|
||||
impl Serialize for str {
|
||||
fn serialize(&self, _record: &Record, key: &'static str, serializer: &mut Serializer) -> result::Result<(), Error> {
|
||||
serializer.emit_str(key, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Serialize for &'a str {
|
||||
fn serialize(&self, _record: &Record, key: &'static str, serializer: &mut Serializer) -> result::Result<(), Error> {
|
||||
serializer.emit_str(key, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Serialize for fmt::Arguments<'a>{
|
||||
fn serialize(&self, _record: &Record, key: &'static str, serializer: &mut Serializer) -> result::Result<(), Error> {
|
||||
serializer.emit_arguments(key, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl SyncSerialize for fmt::Arguments<'static> {}
|
||||
|
||||
impl SyncSerialize for &'static str {}
|
||||
|
||||
impl Serialize for String {
|
||||
fn serialize(&self, _record: &Record, key: &'static str, serializer: &mut Serializer) -> result::Result<(), Error> {
|
||||
serializer.emit_str(key, self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl SyncSerialize for String {}
|
||||
|
||||
impl<T: Serialize> Serialize for Option<T> {
|
||||
fn serialize(&self, record: &Record, key: &'static str, serializer: &mut Serializer) -> result::Result<(), Error> {
|
||||
match *self {
|
||||
Some(ref s) => s.serialize(record, key, serializer),
|
||||
None => serializer.emit_none(key),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Serialize + Send + Sync + 'static> SyncSerialize for Option<T> {}
|
||||
|
||||
|
||||
impl Serialize for Box<Serialize+Send+'static> {
|
||||
fn serialize(&self, record: &Record, key: &'static str, serializer: &mut Serializer) -> result::Result<(), Error> {
|
||||
(**self).serialize(record, key, serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for Arc<T>
|
||||
where T: Serialize
|
||||
{
|
||||
fn serialize(&self, record: &Record, key: &'static str, serializer: &mut Serializer) -> result::Result<(), Error> {
|
||||
(**self).serialize(record, key, serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SyncSerialize for Arc<T> where T: SyncSerialize {}
|
||||
|
||||
impl<T> Serialize for Rc<T>
|
||||
where T: Serialize
|
||||
{
|
||||
fn serialize(&self, record: &Record, key: &'static str, serializer: &mut Serializer) -> result::Result<(), Error> {
|
||||
(**self).serialize(record, key, serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for core::num::Wrapping<T>
|
||||
where T: Serialize
|
||||
{
|
||||
fn serialize(&self, record: &Record, key: &'static str, serializer: &mut Serializer) -> result::Result<(), Error> {
|
||||
self.0.serialize(record, key, serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SyncSerialize for core::num::Wrapping<T> where T: SyncSerialize {}
|
||||
|
||||
impl<S: 'static + Serialize, F> Serialize for F
|
||||
where F: 'static + for<'c, 'd> Fn(&'c Record<'d>) -> S
|
||||
{
|
||||
fn serialize(&self, record: &Record, key: &'static str, serializer: &mut Serializer) -> result::Result<(), Error> {
|
||||
(*self)(record).serialize(record, key, serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: 'static + Serialize, F> SyncSerialize for F
|
||||
where F: 'static + Sync + Send + for<'c, 'd> Fn(&'c Record<'d>) -> S
|
||||
{
|
||||
}
|
||||
|
||||
/// A newtype for non-return based lazy values
|
||||
///
|
||||
/// It's more natural for closures used as lazy values to return `Serialize`
|
||||
/// implementing type, but sometimes that forces an allocation (eg. Strings)
|
||||
///
|
||||
/// In some cases it might make sense for another closure form to be used - one
|
||||
/// taking a serializer as an argument, which avoids lifetimes / allocation issues.
|
||||
///
|
||||
/// Unfortunately, as one `struct` can implement many different closure traits,
|
||||
/// a newtype has to be used to prevent ambiguity.
|
||||
///
|
||||
/// Generally this method should be used only if it avoids a big allocation of
|
||||
/// `Serialize`-implementing type in performance-critical logging statement.
|
||||
///
|
||||
/// TODO: Can `PushLazy` be avoided?
|
||||
pub struct PushLazy<F>(pub F);
|
||||
|
||||
/// A handle to `Serializer` for `PushLazy` closure
|
||||
pub struct ValueSerializer<'a> {
|
||||
record: &'a Record<'a>,
|
||||
key: &'static str,
|
||||
serializer: &'a mut Serializer,
|
||||
done: bool,
|
||||
}
|
||||
|
||||
impl<'a> ValueSerializer<'a> {
|
||||
/// Serialize a value
|
||||
///
|
||||
/// This consumes `self` to prevent serializing one value multiple times
|
||||
pub fn serialize<'b, S: 'b + Serialize>(mut self, s: S) -> result::Result<(), Error> {
|
||||
self.done = true;
|
||||
s.serialize(self.record, self.key, self.serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for ValueSerializer<'a> {
|
||||
fn drop(&mut self) {
|
||||
if !self.done {
|
||||
// unfortunately this gives no change to return serialization errors
|
||||
let _ = self.serializer.emit_unit(self.key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Serialize for PushLazy<F>
|
||||
where F: 'static + for<'c, 'd> Fn(&'c Record<'d>, ValueSerializer<'c>) -> result::Result<(), Error>
|
||||
{
|
||||
fn serialize(&self, record: &Record, key: &'static str, serializer: &mut Serializer) -> result::Result<(), Error> {
|
||||
let ser = ValueSerializer {
|
||||
record: record,
|
||||
key: key,
|
||||
serializer: serializer,
|
||||
done: false,
|
||||
};
|
||||
(self.0)(record, ser)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> SyncSerialize for PushLazy<F>
|
||||
where F: 'static + Sync + Send + for<'c, 'd> Fn(&'c Record<'d>, ValueSerializer<'c>)
|
||||
-> result::Result<(), Error> {
|
||||
}
|
||||
|
||||
impl<A : SyncSerialize> SyncMultiSerialize for (&'static str, A) {
|
||||
fn tail(&self) -> Option<&SyncMultiSerialize> {
|
||||
None
|
||||
}
|
||||
|
||||
fn head(&self) -> (&'static str, &SyncSerialize) {
|
||||
let (ref key, ref val) = *self;
|
||||
(key, val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A : SyncSerialize, R : SyncMultiSerialize> SyncMultiSerialize for (&'static str, A, R) {
|
||||
fn tail(&self) -> Option<&SyncMultiSerialize> {
|
||||
let (_, _, ref tail) = *self;
|
||||
Some(tail)
|
||||
}
|
||||
|
||||
fn head(&self) -> (&'static str, &SyncSerialize) {
|
||||
let (ref key, ref val, _) = *self;
|
||||
(key, val)
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
use super::{Logger, Discard};
|
||||
|
||||
#[test]
|
||||
fn logger_fmt_debug_sanity() {
|
||||
|
||||
let root = Logger::root(Discard, o!("a" => "aa"));
|
||||
let log = root.new(o!("b" => "bb", "c" => "cc"));
|
||||
|
||||
assert_eq!(format!("{:?}", log), "Logger(c, b, a)");
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use {Logger, Discard};
|
||||
/// ensure o! macro expands without error inside a module
|
||||
#[test]
|
||||
fn test_o_macro_expansion() {
|
||||
let _ = Logger::root(Discard, o!("a" => "aa"));
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче