Bug 1878375 - Synchronize vendored Rust libraries with mozilla-central. r=rjl
mozilla-central: 9e49a1b86e40462117bddf9038736c1c3ee22092 comm-central: b83c40ae0dfa3199d277148a91129b6da0e9a128 Differential Revision: https://phabricator.services.mozilla.com/D213168 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
90cf18d341
Коммит
451b12a508
|
@ -3662,12 +3662,6 @@ version = "1.19.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "oneshot-uniffi"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c548d5c78976f6955d72d0ced18c48ca07030f7a1d4024529fedd7c1c01b29c"
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "3.4.0"
|
||||
|
@ -4956,8 +4950,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
|
||||
dependencies = [
|
||||
"smawk",
|
||||
"unicode-linebreak",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -5203,12 +5195,6 @@ version = "1.0.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-linebreak"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.22"
|
||||
|
@ -5232,9 +5218,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
|||
|
||||
[[package]]
|
||||
name = "uniffi"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5566fae48a5cb017005bf9cd622af5236b2a203a13fb548afde3506d3c68277"
|
||||
checksum = "cb3a4c447c50fcda7bc5604a8588b7e1f37ffbfd8838a1516a290398efa7c6f0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"uniffi_build",
|
||||
|
@ -5317,9 +5303,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uniffi_bindgen"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a77bb514bcd4bf27c9bd404d7c3f2a6a8131b957eba9c22cfeb7751c4278e09"
|
||||
checksum = "0be2bc6bafd82c979b0faca77c7b26630d54017de9f5bd5a686ec6ef038ad5d9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"askama",
|
||||
|
@ -5341,9 +5327,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uniffi_build"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45cba427aeb7b3a8b54830c4c915079a7a3c62608dd03dddba1d867a8a023eb4"
|
||||
checksum = "1c59b65d59685ff3a10569287c6419f76487b4052ac52d5a0df38b2253d7f440"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"camino",
|
||||
|
@ -5352,9 +5338,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uniffi_checksum_derive"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae7e5a6c33b1dec3f255f57ec0b6af0f0b2bb3021868be1d5eec7a38e2905ebc"
|
||||
checksum = "d5c400339a9d1d17be34257d0b407e91d64af335e5b4fa49f4bf28467fc8d635"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
|
@ -5362,25 +5348,24 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uniffi_core"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ea3eb5474d50fc149b7e4d86b9c5bd4a61dcc167f0683902bf18ae7bbb3deef"
|
||||
checksum = "a02e67ac9634b10da9e4aa63a29a7920b8f1395eafef1ea659b2dd76dda96906"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"camino",
|
||||
"log",
|
||||
"once_cell",
|
||||
"oneshot-uniffi",
|
||||
"paste",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_macros"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18331d35003f46f0d04047fbe4227291815b83a937a8c32bc057f990962182c4"
|
||||
checksum = "b6f08d5592c669b80a8af5066027098bebec4b4af17a9b8b299bac5f518ab89e"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"camino",
|
||||
|
@ -5396,9 +5381,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uniffi_meta"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7224422c4cfd181c7ca9fca2154abca4d21db962f926f270f996edd38b0c4b8"
|
||||
checksum = "583bab49f2bdf5681f9732f8b67a7e555ad920dbb5427be21450217bf1818189"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
|
@ -5408,9 +5393,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uniffi_testing"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8ce878d0bdfc288b58797044eaaedf748526c56eef3575380bb4d4b19d69eee"
|
||||
checksum = "13963044ca9bde9b709d2eee68bc11dafc7acea144ae0fdc0cf29ed4add44481"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"camino",
|
||||
|
@ -5421,9 +5406,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uniffi_udl"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c43c9ed40a8d20a5c3eae2d23031092db6b96dc8e571beb449ba9757484cea0"
|
||||
checksum = "b92f984bb0d9a06778f256aec963e1e9a80714014f7a90fb0e01008821fe5a97"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"textwrap",
|
||||
|
|
|
@ -13,8 +13,8 @@ gkrust-gtest = ["gkrust"]
|
|||
members = ['xpcom_async', 'moz_http', 'gkrust', 'ews_xpcom', 'gtest']
|
||||
|
||||
[workspace.dependencies]
|
||||
uniffi = { version = "0.27.1" }
|
||||
uniffi_bindgen = { version = "0.27.1" }
|
||||
uniffi = { version = "0.27.3" }
|
||||
uniffi_bindgen = { version = "0.27.3" }
|
||||
rusqlite = { version = "0.31.0" }
|
||||
|
||||
[patch.crates-io]
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"mc_workspace_toml": "d864953b9f7b706553090e5ff5be1895ca729f7fd9b1e7806a9cfc330ab8212268bb5b3337ab706d6d2d0a40f154978f305c572e7884f47080250b15ff658221", "mc_gkrust_toml": "ec12ac730b7f709bd839c1fc9c65f36ae6f82b481902e72769b3d32cfc0a66a6cbf3246a9ab933eca3b3ca06f4f27fe9e88f4706142732460399344681da9e9e", "mc_cargo_lock": "6c80f72aece68ea112aa4478a7a2aba5a806fd2737cc372785474e05deb7e270f951c215bd57ee730e1e484f66fc0d546bf4244d1483b70b24779fac5ece95a2"}
|
||||
{"mc_workspace_toml": "50c105726dd9f7aa5c90114fb6f907234844ce7750dec4e18c3b245b33ae6ba8a44936e692a2ac11271a5cfc1ae8f1f1235482ddb4e72693a9513479d611bc4d", "mc_gkrust_toml": "ec12ac730b7f709bd839c1fc9c65f36ae6f82b481902e72769b3d32cfc0a66a6cbf3246a9ab933eca3b3ca06f4f27fe9e88f4706142732460399344681da9e9e", "mc_cargo_lock": "b39abccbd6f59569ba9b3ff5e994ff336d83a7b0db2cca46c5221592511abc98001feb1a9f374d20b23aa19bb9de33e7388d77a1ac222705fb1c27bb2776598d"}
|
|
@ -1 +0,0 @@
|
|||
{"files":{"CHANGELOG.md":"4ad03d95d5532e8f2551e3e53877e6347c04c32f479c4edf517244ecd5921ac7","Cargo.lock":"5d85bcfda2ee559d243099fb26f3724ae239777d891e780a924804e30f6733ad","Cargo.toml":"07a73ff74274df3a7439fccc8acfe306fae0f51ad79a80edbc54b51a730314c0","README.md":"811ea1c958d5a65583d0223b7ab09bb282e7a51ed60f9a2cb90ef6d555325a68","benches/benches.rs":"67dcc916d0b7e28e396c28dac0499726366e1cb10e9991948d1c881a5abf5faa","check_mem_leaks.sh":"c1ab6ef27997c7f971352ab1c86a184004843c499bc24925da953aefcf1c624c","examples/recv_before_send.rs":"9a3cabcc2878990b61787d0048061b382555a8cd1a08b1ddec63a6e8a4a31e56","examples/recv_before_send_then_drop_sender.rs":"14706c6b4308a690662ceaa47f1699588bd833b3ec020eb9f42f220f3ffc7ae7","examples/recv_ref_before_send.rs":"43699f4720c46b5f138c260b866eb708ddf616e2b442ffa74a97373f4f48d4d0","examples/recv_ref_before_send_then_drop_sender.rs":"a190ed220cb4288d4965485365c9afaed30535cbfad5f8cb7389071b82d67cac","examples/recv_timeout_before_send.rs":"2262aa6531afce7816d43182ad9cbec2c04f3dc129064e11e89452278ce8b163","examples/recv_timeout_before_send_then_drop_sender.rs":"4cc8eade4c211f52f5b9be0f72a5906689b894490f4cb5255525e44106e7a4a8","examples/recv_with_dropped_sender.rs":"7906685053ce1c53ff6c26ce11d3221d4bf5ca3429d1d4d2c28de9237cb151c6","examples/send_before_recv.rs":"5555bd61ad52273b663007794128d8f012fc54272bd3225259b5546221bcd591","examples/send_then_drop_receiver.rs":"c3612de207309098404b057468687a2d2311d07f354b7e046398e35e93c4cdcf","examples/send_with_dropped_receiver.rs":"f5a7762b231a24a0db4397c5139437cba155d09b9dbb59872d662c7923080706","src/errors.rs":"a5aa56bc497dccdbdbe15b9070360f50835c762f11be4ee96e0d25b150168ac9","src/lib.rs":"4bef3602ff4f5d2b42ce963d722a48c9ff07275e75ef6bed7b523e8f45e459fe","src/loombox.rs":"fc85d1c2d3fda432be60f0c4d1d528e5998ec2b738a5b395a242285051b94d65","tests/assert_mem.rs":"b1e5190af01af22e55c7c1cd1ff2711807591f788e4eb8b6c6d89123e146105e","tests/async.rs":"6fd2826e589b94677d4eeed1080deda8bcc429aa05a20d843d1442a3a48ea757","tests/future.rs":"0e71f0293cd5a8c44210e8882aca20cfbf1e3771ecd4e4f6b59b924c0d01dd97","tests/helpers/mod.rs":"19161ed33e0ba8862746f04678d0606dee90205896083f85d8c1dcd4d211ccb0","tests/helpers/waker.rs":"77494d49f62d0d320df3830643c306e06e6e20751d210cf6fa58b238bd96c3f9","tests/loom.rs":"ea350fa424a95581e1871bc0037badecc5a090f28fd10532917abbaf561218ab","tests/raw.rs":"5564615fea811b0061d8ad801356e60e0018ec4e3fb99cc739287ed5b96cb7cf","tests/sync.rs":"1186fa6cdb5a180944fa7d793ccb8be412c4a4e88bb504daa70bc097ee081b06"},"package":"6c548d5c78976f6955d72d0ced18c48ca07030f7a1d4024529fedd7c1c01b29c"}
|
|
@ -1,69 +0,0 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||
|
||||
### Categories each change fall into
|
||||
|
||||
* **Added**: for new features.
|
||||
* **Changed**: for changes in existing functionality.
|
||||
* **Deprecated**: for soon-to-be removed features.
|
||||
* **Removed**: for now removed features.
|
||||
* **Fixed**: for any bug fixes.
|
||||
* **Security**: in case of vulnerabilities.
|
||||
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
|
||||
## [0.1.6] - 2023-09-14
|
||||
### Added
|
||||
* Add `into_raw` and `from_raw` methods on both `Sender` and `Receiver`. Allows passing `oneshot`
|
||||
channels over FFI without an extra layer of heap allocation.
|
||||
|
||||
|
||||
## [0.1.5] - 2022-09-01
|
||||
### Fixed
|
||||
- Handle the UNPARKING state correctly in all recv methods. `try_recv` will now not panic
|
||||
if used on a `Receiver` that is being unparked from an async wait. The other `recv` methods
|
||||
will still panic (as they should), but with a better error message.
|
||||
|
||||
|
||||
## [0.1.4] - 2022-08-30
|
||||
### Changed
|
||||
- Upgrade to Rust edition 2021. Also increases the MSRV to Rust 1.60.
|
||||
- Add null-pointer optimization to `Sender`, `Receiver` and `SendError`.
|
||||
This reduces the call stack size of Sender::send and it makes
|
||||
`Option<Sender>` and `Option<Receiver>` pointer sized (#18).
|
||||
- Relax the memory ordering of all atomic operations from `SeqCst` to the most appropriate
|
||||
lower ordering (#17 + #20).
|
||||
|
||||
### Fixed
|
||||
- Fix undefined behavior due to multiple mutable references to the same channel instance (#18).
|
||||
- Fix race condition that could happen during unparking of a receiving `Receiver` (#17 + #20).
|
||||
|
||||
|
||||
## [0.1.3] - 2021-11-23
|
||||
### Fixed
|
||||
- Keep the *last* `Waker` in `Future::poll`, not the *first* one. Stops breaking the contract
|
||||
on how futures should work.
|
||||
|
||||
|
||||
## [0.1.2] - 2020-08-11
|
||||
### Fixed
|
||||
- Fix unreachable code panic that happened if the `Receiver` of an empty but open channel was
|
||||
polled and then dropped.
|
||||
|
||||
|
||||
## [0.1.1] - 2020-05-10
|
||||
Initial implementation. Supports basically all the (for now) intended functionality.
|
||||
Sender is as lock-free as I think it can get and the receiver can both do thread blocking
|
||||
and be awaited asynchronously. The receiver also has a wait-free `try_recv` method.
|
||||
|
||||
The crate has two features. They are activated by default, but the user can opt out of async
|
||||
support as well as usage of libstd (making the crate `no_std` but still requiring liballoc)
|
||||
|
||||
|
||||
## [0.1.0] - 2019-05-30
|
||||
Name reserved on crate.io by someone other than the author of this crate.
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,64 +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 are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.60.0"
|
||||
name = "oneshot-uniffi"
|
||||
version = "0.1.6"
|
||||
authors = ["Linus Färnstrand <faern@faern.net>"]
|
||||
description = """
|
||||
Patched version of oneshot specifically for the UniFFI project.
|
||||
|
||||
This removes the `loom` target and dependency which helps with UniFFI's downstream consumers.
|
||||
"""
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"oneshot",
|
||||
"spsc",
|
||||
"async",
|
||||
"sync",
|
||||
"channel",
|
||||
]
|
||||
categories = [
|
||||
"asynchronous",
|
||||
"concurrency",
|
||||
]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/faern/oneshot"
|
||||
|
||||
[[bench]]
|
||||
name = "benches"
|
||||
harness = false
|
||||
|
||||
[dev-dependencies.async-std]
|
||||
version = "1"
|
||||
features = ["attributes"]
|
||||
|
||||
[dev-dependencies.criterion]
|
||||
version = "0.3"
|
||||
|
||||
[dev-dependencies.tokio]
|
||||
version = "1"
|
||||
features = [
|
||||
"rt",
|
||||
"rt-multi-thread",
|
||||
"macros",
|
||||
"time",
|
||||
]
|
||||
|
||||
[features]
|
||||
async = []
|
||||
default = [
|
||||
"std",
|
||||
"async",
|
||||
]
|
||||
std = []
|
|
@ -1,94 +0,0 @@
|
|||
# oneshot
|
||||
|
||||
Oneshot spsc (single producer, single consumer) channel. Meaning each channel instance
|
||||
can only transport a single message. This has a few nice outcomes. One thing is that
|
||||
the implementation can be very efficient, utilizing the knowledge that there will
|
||||
only be one message. But more importantly, it allows the API to be expressed in such
|
||||
a way that certain edge cases that you don't want to care about when only sending a
|
||||
single message on a channel does not exist. For example: The sender can't be copied
|
||||
or cloned, and the send method takes ownership and consumes the sender.
|
||||
So you are guaranteed, at the type level, that there can only be one message sent.
|
||||
|
||||
The sender's send method is non-blocking, and potentially lock- and wait-free.
|
||||
See documentation on [Sender::send] for situations where it might not be fully wait-free.
|
||||
The receiver supports both lock- and wait-free `try_recv` as well as indefinite and time
|
||||
limited thread blocking receive operations. The receiver also implements `Future` and
|
||||
supports asynchronously awaiting the message.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
This example sets up a background worker that processes requests coming in on a standard
|
||||
mpsc channel and replies on a oneshot channel provided with each request. The worker can
|
||||
be interacted with both from sync and async contexts since the oneshot receiver
|
||||
can receive both blocking and async.
|
||||
|
||||
```rust
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
type Request = String;
|
||||
|
||||
// Starts a background thread performing some computation on requests sent to it.
|
||||
// Delivers the response back over a oneshot channel.
|
||||
fn spawn_processing_thread() -> mpsc::Sender<(Request, oneshot::Sender<usize>)> {
|
||||
let (request_sender, request_receiver) = mpsc::channel::<(Request, oneshot::Sender<usize>)>();
|
||||
thread::spawn(move || {
|
||||
for (request_data, response_sender) in request_receiver.iter() {
|
||||
let compute_operation = || request_data.len();
|
||||
let _ = response_sender.send(compute_operation()); // <- Send on the oneshot channel
|
||||
}
|
||||
});
|
||||
request_sender
|
||||
}
|
||||
|
||||
let processor = spawn_processing_thread();
|
||||
|
||||
// If compiled with `std` the library can receive messages with timeout on regular threads
|
||||
#[cfg(feature = "std")] {
|
||||
let (response_sender, response_receiver) = oneshot::channel();
|
||||
let request = Request::from("data from sync thread");
|
||||
|
||||
processor.send((request, response_sender)).expect("Processor down");
|
||||
match response_receiver.recv_timeout(Duration::from_secs(1)) { // <- Receive on the oneshot channel
|
||||
Ok(result) => println!("Processor returned {}", result),
|
||||
Err(oneshot::RecvTimeoutError::Timeout) => eprintln!("Processor was too slow"),
|
||||
Err(oneshot::RecvTimeoutError::Disconnected) => panic!("Processor exited"),
|
||||
}
|
||||
}
|
||||
|
||||
// If compiled with the `async` feature, the `Receiver` can be awaited in an async context
|
||||
#[cfg(feature = "async")] {
|
||||
tokio::runtime::Runtime::new()
|
||||
.unwrap()
|
||||
.block_on(async move {
|
||||
let (response_sender, response_receiver) = oneshot::channel();
|
||||
let request = Request::from("data from sync thread");
|
||||
|
||||
processor.send((request, response_sender)).expect("Processor down");
|
||||
match response_receiver.await { // <- Receive on the oneshot channel asynchronously
|
||||
Ok(result) => println!("Processor returned {}", result),
|
||||
Err(_e) => panic!("Processor exited"),
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Sync vs async
|
||||
|
||||
The main motivation for writing this library was that there were no (known to me) channel
|
||||
implementations allowing you to seamlessly send messages between a normal thread and an async
|
||||
task, or the other way around. If message passing is the way you are communicating, of course
|
||||
that should work smoothly between the sync and async parts of the program!
|
||||
|
||||
This library achieves that by having a fast and cheap send operation that can
|
||||
be used in both sync threads and async tasks. The receiver has both thread blocking
|
||||
receive methods for synchronous usage, and implements `Future` for asynchronous usage.
|
||||
|
||||
The receiving endpoint of this channel implements Rust's `Future` trait and can be waited on
|
||||
in an asynchronous task. This implementation is completely executor/runtime agnostic. It should
|
||||
be possible to use this library with any executor.
|
||||
|
||||
|
||||
License: MIT OR Apache-2.0
|
|
@ -1,122 +0,0 @@
|
|||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use std::mem;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
criterion_group!(benches, bench);
|
||||
criterion_main!(benches);
|
||||
|
||||
macro_rules! bench_send_and_recv {
|
||||
($c:expr, $($type:ty => $value:expr);+) => {
|
||||
// Sanity check that all $values are of $type.
|
||||
$(let _: $type = $value;)*
|
||||
{
|
||||
let mut group = $c.benchmark_group("create_channel");
|
||||
$(group.bench_function(stringify!($type), |b| {
|
||||
b.iter(oneshot::channel::<$type>)
|
||||
});)*
|
||||
group.finish();
|
||||
}
|
||||
{
|
||||
let mut group = $c.benchmark_group("create_and_send");
|
||||
$(group.bench_function(stringify!($type), |b| {
|
||||
b.iter(|| {
|
||||
let (sender, _receiver) = oneshot::channel();
|
||||
sender.send(black_box($value)).unwrap()
|
||||
});
|
||||
});)*
|
||||
group.finish();
|
||||
}
|
||||
{
|
||||
let mut group = $c.benchmark_group("create_and_send_on_closed");
|
||||
$(group.bench_function(stringify!($type), |b| {
|
||||
b.iter(|| {
|
||||
let (sender, _) = oneshot::channel();
|
||||
sender.send(black_box($value)).unwrap_err()
|
||||
});
|
||||
});)*
|
||||
group.finish();
|
||||
}
|
||||
{
|
||||
let mut group = $c.benchmark_group("create_send_and_recv");
|
||||
$(group.bench_function(stringify!($type), |b| {
|
||||
b.iter(|| {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
sender.send(black_box($value)).unwrap();
|
||||
receiver.recv().unwrap()
|
||||
});
|
||||
});)*
|
||||
group.finish();
|
||||
}
|
||||
{
|
||||
let mut group = $c.benchmark_group("create_send_and_recv_ref");
|
||||
$(group.bench_function(stringify!($type), |b| {
|
||||
b.iter(|| {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
sender.send(black_box($value)).unwrap();
|
||||
receiver.recv_ref().unwrap()
|
||||
});
|
||||
});)*
|
||||
group.finish();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn bench(c: &mut Criterion) {
|
||||
bench_send_and_recv!(c,
|
||||
() => ();
|
||||
u8 => 7u8;
|
||||
usize => 9876usize;
|
||||
u128 => 1234567u128;
|
||||
[u8; 64] => [0b10101010u8; 64];
|
||||
[u8; 4096] => [0b10101010u8; 4096]
|
||||
);
|
||||
|
||||
bench_try_recv(c);
|
||||
bench_recv_deadline_now(c);
|
||||
bench_recv_timeout_zero(c);
|
||||
}
|
||||
|
||||
fn bench_try_recv(c: &mut Criterion) {
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
c.bench_function("try_recv_empty", |b| {
|
||||
b.iter(|| receiver.try_recv().unwrap_err())
|
||||
});
|
||||
mem::drop(sender);
|
||||
c.bench_function("try_recv_empty_closed", |b| {
|
||||
b.iter(|| receiver.try_recv().unwrap_err())
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_recv_deadline_now(c: &mut Criterion) {
|
||||
let now = Instant::now();
|
||||
{
|
||||
let (_sender, receiver) = oneshot::channel::<u128>();
|
||||
c.bench_function("recv_deadline_now", |b| {
|
||||
b.iter(|| receiver.recv_deadline(now).unwrap_err())
|
||||
});
|
||||
}
|
||||
{
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
mem::drop(sender);
|
||||
c.bench_function("recv_deadline_now_closed", |b| {
|
||||
b.iter(|| receiver.recv_deadline(now).unwrap_err())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn bench_recv_timeout_zero(c: &mut Criterion) {
|
||||
let zero = Duration::from_nanos(0);
|
||||
{
|
||||
let (_sender, receiver) = oneshot::channel::<u128>();
|
||||
c.bench_function("recv_timeout_zero", |b| {
|
||||
b.iter(|| receiver.recv_timeout(zero).unwrap_err())
|
||||
});
|
||||
}
|
||||
{
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
mem::drop(sender);
|
||||
c.bench_function("recv_timeout_zero_closed", |b| {
|
||||
b.iter(|| receiver.recv_timeout(zero).unwrap_err())
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
for example_path in examples/*.rs; do
|
||||
example_filename=$(basename -- $example_path)
|
||||
example=${example_filename%.*}
|
||||
echo $example
|
||||
cargo valgrind run --example "$example"
|
||||
done
|
|
@ -1,18 +0,0 @@
|
|||
#[cfg(feature = "std")]
|
||||
fn main() {
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let t = thread::spawn(move || {
|
||||
thread::sleep(Duration::from_millis(2));
|
||||
sender.send(9u128).unwrap();
|
||||
});
|
||||
assert_eq!(receiver.recv(), Ok(9));
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn main() {
|
||||
panic!("This example is only for when the \"sync\" feature is used");
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
#[cfg(feature = "std")]
|
||||
fn main() {
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
let t = thread::spawn(move || {
|
||||
thread::sleep(Duration::from_millis(2));
|
||||
std::mem::drop(sender);
|
||||
});
|
||||
assert!(receiver.recv().is_err());
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn main() {
|
||||
panic!("This example is only for when the \"sync\" feature is used");
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
#[cfg(feature = "std")]
|
||||
fn main() {
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let t = thread::spawn(move || {
|
||||
thread::sleep(Duration::from_millis(2));
|
||||
sender.send(9u128).unwrap();
|
||||
});
|
||||
assert_eq!(receiver.recv_ref(), Ok(9));
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn main() {
|
||||
panic!("This example is only for when the \"sync\" feature is used");
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
#[cfg(feature = "std")]
|
||||
fn main() {
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
let t = thread::spawn(move || {
|
||||
thread::sleep(Duration::from_millis(2));
|
||||
std::mem::drop(sender);
|
||||
});
|
||||
assert!(receiver.recv_ref().is_err());
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn main() {
|
||||
panic!("This example is only for when the \"sync\" feature is used");
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
#[cfg(feature = "std")]
|
||||
fn main() {
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let t = thread::spawn(move || {
|
||||
thread::sleep(Duration::from_millis(2));
|
||||
sender.send(9u128).unwrap();
|
||||
});
|
||||
assert_eq!(receiver.recv_timeout(Duration::from_millis(100)), Ok(9));
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn main() {
|
||||
panic!("This example is only for when the \"sync\" feature is used");
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
#[cfg(feature = "std")]
|
||||
fn main() {
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
let t = thread::spawn(move || {
|
||||
thread::sleep(Duration::from_millis(2));
|
||||
std::mem::drop(sender);
|
||||
});
|
||||
assert!(receiver.recv_timeout(Duration::from_millis(100)).is_err());
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn main() {
|
||||
panic!("This example is only for when the \"sync\" feature is used");
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#[cfg(feature = "std")]
|
||||
fn main() {
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
std::mem::drop(sender);
|
||||
receiver.recv().unwrap_err();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn main() {
|
||||
panic!("This example is only for when the \"sync\" feature is used");
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#[cfg(feature = "std")]
|
||||
fn main() {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
assert!(sender.send(19i128).is_ok());
|
||||
assert_eq!(receiver.recv(), Ok(19i128));
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn main() {
|
||||
panic!("This example is only for when the \"sync\" feature is used");
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
use std::mem;
|
||||
|
||||
fn main() {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
assert!(sender.send(19i128).is_ok());
|
||||
mem::drop(receiver);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
use std::mem;
|
||||
|
||||
fn main() {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
mem::drop(receiver);
|
||||
let send_error = sender.send(5u128).unwrap_err();
|
||||
assert_eq!(send_error.into_inner(), 5);
|
||||
}
|
|
@ -1,147 +0,0 @@
|
|||
use super::{dealloc, Channel};
|
||||
use core::fmt;
|
||||
use core::mem;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
/// An error returned when trying to send on a closed channel. Returned from
|
||||
/// [`Sender::send`](crate::Sender::send) if the corresponding [`Receiver`](crate::Receiver)
|
||||
/// has already been dropped.
|
||||
///
|
||||
/// The message that could not be sent can be retreived again with [`SendError::into_inner`].
|
||||
pub struct SendError<T> {
|
||||
channel_ptr: NonNull<Channel<T>>,
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for SendError<T> {}
|
||||
unsafe impl<T: Sync> Sync for SendError<T> {}
|
||||
|
||||
impl<T> SendError<T> {
|
||||
/// # Safety
|
||||
///
|
||||
/// By calling this function, the caller semantically transfers ownership of the
|
||||
/// channel's resources to the created `SendError`. Thus the caller must ensure that the
|
||||
/// pointer is not used in a way which would violate this ownership transfer. Moreover,
|
||||
/// the caller must assert that the channel contains a valid, initialized message.
|
||||
pub(crate) const unsafe fn new(channel_ptr: NonNull<Channel<T>>) -> Self {
|
||||
Self { channel_ptr }
|
||||
}
|
||||
|
||||
/// Consumes the error and returns the message that failed to be sent.
|
||||
#[inline]
|
||||
pub fn into_inner(self) -> T {
|
||||
let channel_ptr = self.channel_ptr;
|
||||
|
||||
// Don't run destructor if we consumed ourselves. Freeing happens here.
|
||||
mem::forget(self);
|
||||
|
||||
// SAFETY: we have ownership of the channel
|
||||
let channel: &Channel<T> = unsafe { channel_ptr.as_ref() };
|
||||
|
||||
// SAFETY: we know that the message is initialized according to the safety requirements of
|
||||
// `new`
|
||||
let message = unsafe { channel.take_message() };
|
||||
|
||||
// SAFETY: we own the channel
|
||||
unsafe { dealloc(channel_ptr) };
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
/// Get a reference to the message that failed to be sent.
|
||||
#[inline]
|
||||
pub fn as_inner(&self) -> &T {
|
||||
unsafe { self.channel_ptr.as_ref().message().assume_init_ref() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for SendError<T> {
|
||||
fn drop(&mut self) {
|
||||
// SAFETY: we have ownership of the channel and require that the message is initialized
|
||||
// upon construction
|
||||
unsafe {
|
||||
self.channel_ptr.as_ref().drop_message();
|
||||
dealloc(self.channel_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Display for SendError<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
"sending on a closed channel".fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for SendError<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "SendError<{}>(_)", stringify!(T))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T> std::error::Error for SendError<T> {}
|
||||
|
||||
/// An error returned from the blocking [`Receiver::recv`](crate::Receiver::recv) method.
|
||||
///
|
||||
/// The receive operation can only fail if the corresponding [`Sender`](crate::Sender) was dropped
|
||||
/// before sending any message, or if a message has already been sent and received on the channel.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct RecvError;
|
||||
|
||||
impl fmt::Display for RecvError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
"receiving on a closed channel".fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for RecvError {}
|
||||
|
||||
/// An error returned when failing to receive a message in the non-blocking
|
||||
/// [`Receiver::try_recv`](crate::Receiver::try_recv).
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum TryRecvError {
|
||||
/// The channel is still open, but there was no message present in it.
|
||||
Empty,
|
||||
|
||||
/// The channel is closed. Either the sender was dropped before sending any message, or the
|
||||
/// message has already been extracted from the receiver.
|
||||
Disconnected,
|
||||
}
|
||||
|
||||
impl fmt::Display for TryRecvError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let msg = match self {
|
||||
TryRecvError::Empty => "receiving on an empty channel",
|
||||
TryRecvError::Disconnected => "receiving on a closed channel",
|
||||
};
|
||||
msg.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for TryRecvError {}
|
||||
|
||||
/// An error returned when failing to receive a message in
|
||||
/// [`Receiver::recv_timeout`](crate::Receiver::recv_timeout).
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum RecvTimeoutError {
|
||||
/// No message arrived on the channel before the timeout was reached. The channel is still open.
|
||||
Timeout,
|
||||
|
||||
/// The channel is closed. Either the sender was dropped before sending any message, or the
|
||||
/// message has already been extracted from the receiver.
|
||||
Disconnected,
|
||||
}
|
||||
|
||||
impl fmt::Display for RecvTimeoutError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let msg = match self {
|
||||
RecvTimeoutError::Timeout => "timed out waiting on channel",
|
||||
RecvTimeoutError::Disconnected => "channel is empty and sending half is closed",
|
||||
};
|
||||
msg.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for RecvTimeoutError {}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,151 +0,0 @@
|
|||
use core::{borrow, fmt, hash, mem, ptr};
|
||||
use loom::alloc;
|
||||
|
||||
pub struct Box<T: ?Sized> {
|
||||
ptr: *mut T,
|
||||
}
|
||||
|
||||
impl<T> Box<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
let layout = alloc::Layout::new::<T>();
|
||||
let ptr = unsafe { alloc::alloc(layout) } as *mut T;
|
||||
unsafe { ptr::write(ptr, value) };
|
||||
Self { ptr }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Box<T> {
|
||||
#[inline]
|
||||
pub fn into_raw(b: Box<T>) -> *mut T {
|
||||
let ptr = b.ptr;
|
||||
mem::forget(b);
|
||||
ptr
|
||||
}
|
||||
|
||||
pub const unsafe fn from_raw(ptr: *mut T) -> Box<T> {
|
||||
Self { ptr }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Drop for Box<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let size = mem::size_of_val(&*self.ptr);
|
||||
let align = mem::align_of_val(&*self.ptr);
|
||||
let layout = alloc::Layout::from_size_align(size, align).unwrap();
|
||||
ptr::drop_in_place(self.ptr);
|
||||
alloc::dealloc(self.ptr as *mut u8, layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for Box<T> {}
|
||||
unsafe impl<T: Sync> Sync for Box<T> {}
|
||||
|
||||
impl<T: ?Sized> core::ops::Deref for Box<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
unsafe { &*self.ptr }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> core::ops::DerefMut for Box<T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
unsafe { &mut *self.ptr }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> borrow::Borrow<T> for Box<T> {
|
||||
fn borrow(&self) -> &T {
|
||||
&**self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> borrow::BorrowMut<T> for Box<T> {
|
||||
fn borrow_mut(&mut self) -> &mut T {
|
||||
&mut **self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> AsRef<T> for Box<T> {
|
||||
fn as_ref(&self) -> &T {
|
||||
&**self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> AsMut<T> for Box<T> {
|
||||
fn as_mut(&mut self) -> &mut T {
|
||||
&mut **self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Display + ?Sized> fmt::Display for Box<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug + ?Sized> fmt::Debug for Box<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Clone for Box<T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Box<T> {
|
||||
Self::new(self.as_ref().clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + PartialEq> PartialEq for Box<T> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Box<T>) -> bool {
|
||||
PartialEq::eq(&**self, &**other)
|
||||
}
|
||||
|
||||
#[allow(clippy::partialeq_ne_impl)]
|
||||
#[inline]
|
||||
fn ne(&self, other: &Box<T>) -> bool {
|
||||
PartialEq::ne(&**self, &**other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Eq> Eq for Box<T> {}
|
||||
|
||||
impl<T: ?Sized + PartialOrd> PartialOrd for Box<T> {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Box<T>) -> Option<core::cmp::Ordering> {
|
||||
PartialOrd::partial_cmp(&**self, &**other)
|
||||
}
|
||||
#[inline]
|
||||
fn lt(&self, other: &Box<T>) -> bool {
|
||||
PartialOrd::lt(&**self, &**other)
|
||||
}
|
||||
#[inline]
|
||||
fn le(&self, other: &Box<T>) -> bool {
|
||||
PartialOrd::le(&**self, &**other)
|
||||
}
|
||||
#[inline]
|
||||
fn ge(&self, other: &Box<T>) -> bool {
|
||||
PartialOrd::ge(&**self, &**other)
|
||||
}
|
||||
#[inline]
|
||||
fn gt(&self, other: &Box<T>) -> bool {
|
||||
PartialOrd::gt(&**self, &**other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Ord> Ord for Box<T> {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Box<T>) -> core::cmp::Ordering {
|
||||
Ord::cmp(&**self, &**other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + hash::Hash> hash::Hash for Box<T> {
|
||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
use oneshot::{Receiver, Sender};
|
||||
use std::mem;
|
||||
|
||||
/// Just sanity check that both channel endpoints stay the size of a single pointer.
|
||||
#[test]
|
||||
fn channel_endpoints_single_pointer() {
|
||||
const PTR_SIZE: usize = mem::size_of::<*const ()>();
|
||||
|
||||
assert_eq!(mem::size_of::<Sender<()>>(), PTR_SIZE);
|
||||
assert_eq!(mem::size_of::<Receiver<()>>(), PTR_SIZE);
|
||||
|
||||
assert_eq!(mem::size_of::<Sender<u8>>(), PTR_SIZE);
|
||||
assert_eq!(mem::size_of::<Receiver<u8>>(), PTR_SIZE);
|
||||
|
||||
assert_eq!(mem::size_of::<Sender<[u8; 1024]>>(), PTR_SIZE);
|
||||
assert_eq!(mem::size_of::<Receiver<[u8; 1024]>>(), PTR_SIZE);
|
||||
|
||||
assert_eq!(mem::size_of::<Option<Sender<[u8; 1024]>>>(), PTR_SIZE);
|
||||
assert_eq!(mem::size_of::<Option<Receiver<[u8; 1024]>>>(), PTR_SIZE);
|
||||
}
|
||||
|
||||
/// Check that the `SendError` stays small. Useful to automatically detect if it is refactored
|
||||
/// to become large. We do not want the stack requirement for calling `Sender::send` to grow.
|
||||
#[test]
|
||||
fn error_sizes() {
|
||||
const PTR_SIZE: usize = mem::size_of::<usize>();
|
||||
|
||||
assert_eq!(mem::size_of::<oneshot::SendError<()>>(), PTR_SIZE);
|
||||
assert_eq!(mem::size_of::<oneshot::SendError<u8>>(), PTR_SIZE);
|
||||
assert_eq!(mem::size_of::<oneshot::SendError<[u8; 1024]>>(), PTR_SIZE);
|
||||
|
||||
// The type returned from `Sender::send` is also just pointer sized
|
||||
assert_eq!(
|
||||
mem::size_of::<Result<(), oneshot::SendError<[u8; 1024]>>>(),
|
||||
PTR_SIZE
|
||||
);
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
#![cfg(all(feature = "async", not(loom)))]
|
||||
|
||||
use core::mem;
|
||||
use core::time::Duration;
|
||||
|
||||
mod helpers;
|
||||
use helpers::DropCounter;
|
||||
|
||||
#[tokio::test]
|
||||
async fn send_before_await_tokio() {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
assert!(sender.send(19i128).is_ok());
|
||||
assert_eq!(receiver.await, Ok(19i128));
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn send_before_await_async_std() {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
assert!(sender.send(19i128).is_ok());
|
||||
assert_eq!(receiver.await, Ok(19i128));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn await_with_dropped_sender_tokio() {
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
mem::drop(sender);
|
||||
receiver.await.unwrap_err();
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn await_with_dropped_sender_async_std() {
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
mem::drop(sender);
|
||||
receiver.await.unwrap_err();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn await_before_send_tokio() {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let (message, counter) = DropCounter::new(79u128);
|
||||
let t = tokio::spawn(async move {
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
sender.send(message)
|
||||
});
|
||||
let returned_message = receiver.await.unwrap();
|
||||
assert_eq!(counter.count(), 0);
|
||||
assert_eq!(*returned_message.value(), 79u128);
|
||||
mem::drop(returned_message);
|
||||
assert_eq!(counter.count(), 1);
|
||||
t.await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn await_before_send_async_std() {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let (message, counter) = DropCounter::new(79u128);
|
||||
let t = async_std::task::spawn(async move {
|
||||
async_std::task::sleep(Duration::from_millis(10)).await;
|
||||
sender.send(message)
|
||||
});
|
||||
let returned_message = receiver.await.unwrap();
|
||||
assert_eq!(counter.count(), 0);
|
||||
assert_eq!(*returned_message.value(), 79u128);
|
||||
mem::drop(returned_message);
|
||||
assert_eq!(counter.count(), 1);
|
||||
t.await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn await_before_send_then_drop_sender_tokio() {
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
let t = tokio::spawn(async {
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
mem::drop(sender);
|
||||
});
|
||||
assert!(receiver.await.is_err());
|
||||
t.await.unwrap();
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn await_before_send_then_drop_sender_async_std() {
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
let t = async_std::task::spawn(async {
|
||||
async_std::task::sleep(Duration::from_millis(10)).await;
|
||||
mem::drop(sender);
|
||||
});
|
||||
assert!(receiver.await.is_err());
|
||||
t.await;
|
||||
}
|
||||
|
||||
// Tests that the Receiver handles being used synchronously even after being polled
|
||||
#[tokio::test]
|
||||
async fn poll_future_and_then_try_recv() {
|
||||
use core::future::Future;
|
||||
use core::pin::Pin;
|
||||
use core::task::{self, Poll};
|
||||
|
||||
struct StupidReceiverFuture(oneshot::Receiver<()>);
|
||||
|
||||
impl Future for StupidReceiverFuture {
|
||||
type Output = Result<(), oneshot::RecvError>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
|
||||
let poll_result = Future::poll(Pin::new(&mut self.0), cx);
|
||||
self.0.try_recv().expect_err("Should never be a message");
|
||||
poll_result
|
||||
}
|
||||
}
|
||||
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let t = tokio::spawn(async {
|
||||
tokio::time::sleep(Duration::from_millis(20)).await;
|
||||
mem::drop(sender);
|
||||
});
|
||||
StupidReceiverFuture(receiver).await.unwrap_err();
|
||||
t.await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn poll_receiver_then_drop_it() {
|
||||
let (sender, receiver) = oneshot::channel::<()>();
|
||||
// This will poll the receiver and then give up after 100 ms.
|
||||
tokio::time::timeout(Duration::from_millis(100), receiver)
|
||||
.await
|
||||
.unwrap_err();
|
||||
// Make sure the receiver has been dropped by the runtime.
|
||||
assert!(sender.send(()).is_err());
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
#![cfg(feature = "async")]
|
||||
|
||||
use core::{future, mem, pin, task};
|
||||
|
||||
#[cfg(loom)]
|
||||
pub use loom::sync::{Arc, Mutex};
|
||||
#[cfg(not(loom))]
|
||||
pub use std::sync::{Arc, Mutex};
|
||||
|
||||
mod helpers;
|
||||
use helpers::maybe_loom_model;
|
||||
|
||||
#[test]
|
||||
fn multiple_receiver_polls_keeps_only_latest_waker() {
|
||||
#[derive(Default)]
|
||||
struct MockWaker {
|
||||
cloned: usize,
|
||||
dropped: usize,
|
||||
}
|
||||
|
||||
fn clone_mock_waker(waker: *const ()) -> task::RawWaker {
|
||||
let mock_waker = unsafe { Arc::from_raw(waker as *const Mutex<MockWaker>) };
|
||||
mock_waker.lock().unwrap().cloned += 1;
|
||||
let new_waker =
|
||||
task::RawWaker::new(Arc::into_raw(mock_waker.clone()) as *const (), &VTABLE);
|
||||
mem::forget(mock_waker);
|
||||
new_waker
|
||||
}
|
||||
|
||||
fn drop_mock_waker(waker: *const ()) {
|
||||
let mock_waker = unsafe { Arc::from_raw(waker as *const Mutex<MockWaker>) };
|
||||
mock_waker.lock().unwrap().dropped += 1;
|
||||
}
|
||||
|
||||
const VTABLE: task::RawWakerVTable =
|
||||
task::RawWakerVTable::new(clone_mock_waker, |_| (), |_| (), drop_mock_waker);
|
||||
|
||||
maybe_loom_model(|| {
|
||||
let mock_waker1 = Arc::new(Mutex::new(MockWaker::default()));
|
||||
let raw_waker1 =
|
||||
task::RawWaker::new(Arc::into_raw(mock_waker1.clone()) as *const (), &VTABLE);
|
||||
let waker1 = unsafe { task::Waker::from_raw(raw_waker1) };
|
||||
let mut context1 = task::Context::from_waker(&waker1);
|
||||
|
||||
let (_sender, mut receiver) = oneshot::channel::<()>();
|
||||
|
||||
let poll_result = future::Future::poll(pin::Pin::new(&mut receiver), &mut context1);
|
||||
assert_eq!(poll_result, task::Poll::Pending);
|
||||
assert_eq!(mock_waker1.lock().unwrap().cloned, 1);
|
||||
assert_eq!(mock_waker1.lock().unwrap().dropped, 0);
|
||||
|
||||
let mock_waker2 = Arc::new(Mutex::new(MockWaker::default()));
|
||||
let raw_waker2 =
|
||||
task::RawWaker::new(Arc::into_raw(mock_waker2.clone()) as *const (), &VTABLE);
|
||||
let waker2 = unsafe { task::Waker::from_raw(raw_waker2) };
|
||||
let mut context2 = task::Context::from_waker(&waker2);
|
||||
|
||||
let poll_result = future::Future::poll(pin::Pin::new(&mut receiver), &mut context2);
|
||||
assert_eq!(poll_result, task::Poll::Pending);
|
||||
assert_eq!(mock_waker2.lock().unwrap().cloned, 1);
|
||||
assert_eq!(mock_waker2.lock().unwrap().dropped, 0);
|
||||
assert_eq!(mock_waker1.lock().unwrap().cloned, 1);
|
||||
assert_eq!(mock_waker1.lock().unwrap().dropped, 1);
|
||||
});
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(not(loom))]
|
||||
use alloc::sync::Arc;
|
||||
#[cfg(not(loom))]
|
||||
use core::sync::atomic::{AtomicUsize, Ordering::SeqCst};
|
||||
#[cfg(loom)]
|
||||
use loom::sync::{
|
||||
atomic::{AtomicUsize, Ordering::SeqCst},
|
||||
Arc,
|
||||
};
|
||||
|
||||
#[cfg(loom)]
|
||||
pub mod waker;
|
||||
|
||||
pub fn maybe_loom_model(test: impl Fn() + Sync + Send + 'static) {
|
||||
#[cfg(loom)]
|
||||
loom::model(test);
|
||||
#[cfg(not(loom))]
|
||||
test();
|
||||
}
|
||||
|
||||
pub struct DropCounter<T> {
|
||||
drop_count: Arc<AtomicUsize>,
|
||||
value: Option<T>,
|
||||
}
|
||||
|
||||
pub struct DropCounterHandle(Arc<AtomicUsize>);
|
||||
|
||||
impl<T> DropCounter<T> {
|
||||
pub fn new(value: T) -> (Self, DropCounterHandle) {
|
||||
let drop_count = Arc::new(AtomicUsize::new(0));
|
||||
(
|
||||
Self {
|
||||
drop_count: drop_count.clone(),
|
||||
value: Some(value),
|
||||
},
|
||||
DropCounterHandle(drop_count),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn value(&self) -> &T {
|
||||
self.value.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn into_value(mut self) -> T {
|
||||
self.value.take().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl DropCounterHandle {
|
||||
pub fn count(&self) -> usize {
|
||||
self.0.load(SeqCst)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for DropCounter<T> {
|
||||
fn drop(&mut self) {
|
||||
self.drop_count.fetch_add(1, SeqCst);
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
//! Creates a Waker that can be observed from tests.
|
||||
|
||||
use std::mem::forget;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::task::{RawWaker, RawWakerVTable, Waker};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct WakerHandle {
|
||||
clone_count: AtomicU32,
|
||||
drop_count: AtomicU32,
|
||||
wake_count: AtomicU32,
|
||||
}
|
||||
|
||||
impl WakerHandle {
|
||||
pub fn clone_count(&self) -> u32 {
|
||||
self.clone_count.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn drop_count(&self) -> u32 {
|
||||
self.drop_count.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn wake_count(&self) -> u32 {
|
||||
self.wake_count.load(Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn waker() -> (Waker, Arc<WakerHandle>) {
|
||||
let waker_handle = Arc::new(WakerHandle::default());
|
||||
let waker_handle_ptr = Arc::into_raw(waker_handle.clone());
|
||||
let raw_waker = RawWaker::new(waker_handle_ptr as *const _, waker_vtable());
|
||||
(unsafe { Waker::from_raw(raw_waker) }, waker_handle)
|
||||
}
|
||||
|
||||
pub(super) fn waker_vtable() -> &'static RawWakerVTable {
|
||||
&RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw)
|
||||
}
|
||||
|
||||
unsafe fn clone_raw(data: *const ()) -> RawWaker {
|
||||
let handle: Arc<WakerHandle> = Arc::from_raw(data as *const _);
|
||||
handle.clone_count.fetch_add(1, Ordering::Relaxed);
|
||||
forget(handle.clone());
|
||||
forget(handle);
|
||||
RawWaker::new(data, waker_vtable())
|
||||
}
|
||||
|
||||
unsafe fn wake_raw(data: *const ()) {
|
||||
let handle: Arc<WakerHandle> = Arc::from_raw(data as *const _);
|
||||
handle.wake_count.fetch_add(1, Ordering::Relaxed);
|
||||
handle.drop_count.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
unsafe fn wake_by_ref_raw(data: *const ()) {
|
||||
let handle: Arc<WakerHandle> = Arc::from_raw(data as *const _);
|
||||
handle.wake_count.fetch_add(1, Ordering::Relaxed);
|
||||
forget(handle)
|
||||
}
|
||||
|
||||
unsafe fn drop_raw(data: *const ()) {
|
||||
let handle: Arc<WakerHandle> = Arc::from_raw(data as *const _);
|
||||
handle.drop_count.fetch_add(1, Ordering::Relaxed);
|
||||
drop(handle)
|
||||
}
|
|
@ -1,223 +0,0 @@
|
|||
#![cfg(loom)]
|
||||
|
||||
use oneshot::TryRecvError;
|
||||
|
||||
use loom::hint;
|
||||
use loom::thread;
|
||||
#[cfg(feature = "async")]
|
||||
use std::future::Future;
|
||||
#[cfg(feature = "async")]
|
||||
use std::pin::Pin;
|
||||
#[cfg(feature = "async")]
|
||||
use std::task::{self, Poll};
|
||||
#[cfg(feature = "std")]
|
||||
use std::time::Duration;
|
||||
|
||||
mod helpers;
|
||||
|
||||
#[test]
|
||||
fn try_recv() {
|
||||
loom::model(|| {
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
|
||||
let t = thread::spawn(move || loop {
|
||||
match receiver.try_recv() {
|
||||
Ok(msg) => break msg,
|
||||
Err(TryRecvError::Empty) => hint::spin_loop(),
|
||||
Err(TryRecvError::Disconnected) => panic!("Should not be disconnected"),
|
||||
}
|
||||
});
|
||||
|
||||
assert!(sender.send(19).is_ok());
|
||||
assert_eq!(t.join().unwrap(), 19);
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn send_recv_different_threads() {
|
||||
loom::model(|| {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let t2 = thread::spawn(move || {
|
||||
assert_eq!(receiver.recv_timeout(Duration::from_millis(1)), Ok(9));
|
||||
});
|
||||
let t1 = thread::spawn(move || {
|
||||
sender.send(9u128).unwrap();
|
||||
});
|
||||
t1.join().unwrap();
|
||||
t2.join().unwrap();
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn recv_drop_sender_different_threads() {
|
||||
loom::model(|| {
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
let t2 = thread::spawn(move || {
|
||||
assert!(receiver.recv_timeout(Duration::from_millis(0)).is_err());
|
||||
});
|
||||
let t1 = thread::spawn(move || {
|
||||
drop(sender);
|
||||
});
|
||||
t1.join().unwrap();
|
||||
t2.join().unwrap();
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn async_recv() {
|
||||
loom::model(|| {
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
let t1 = thread::spawn(move || {
|
||||
sender.send(987).unwrap();
|
||||
});
|
||||
assert_eq!(loom::future::block_on(receiver), Ok(987));
|
||||
t1.join().unwrap();
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn send_then_poll() {
|
||||
loom::model(|| {
|
||||
let (sender, mut receiver) = oneshot::channel::<u128>();
|
||||
sender.send(1234).unwrap();
|
||||
|
||||
let (waker, waker_handle) = helpers::waker::waker();
|
||||
let mut context = task::Context::from_waker(&waker);
|
||||
|
||||
assert_eq!(
|
||||
Pin::new(&mut receiver).poll(&mut context),
|
||||
Poll::Ready(Ok(1234))
|
||||
);
|
||||
assert_eq!(waker_handle.clone_count(), 0);
|
||||
assert_eq!(waker_handle.drop_count(), 0);
|
||||
assert_eq!(waker_handle.wake_count(), 0);
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn poll_then_send() {
|
||||
loom::model(|| {
|
||||
let (sender, mut receiver) = oneshot::channel::<u128>();
|
||||
|
||||
let (waker, waker_handle) = helpers::waker::waker();
|
||||
let mut context = task::Context::from_waker(&waker);
|
||||
|
||||
assert_eq!(Pin::new(&mut receiver).poll(&mut context), Poll::Pending);
|
||||
assert_eq!(waker_handle.clone_count(), 1);
|
||||
assert_eq!(waker_handle.drop_count(), 0);
|
||||
assert_eq!(waker_handle.wake_count(), 0);
|
||||
|
||||
sender.send(1234).unwrap();
|
||||
assert_eq!(waker_handle.clone_count(), 1);
|
||||
assert_eq!(waker_handle.drop_count(), 1);
|
||||
assert_eq!(waker_handle.wake_count(), 1);
|
||||
|
||||
assert_eq!(
|
||||
Pin::new(&mut receiver).poll(&mut context),
|
||||
Poll::Ready(Ok(1234))
|
||||
);
|
||||
assert_eq!(waker_handle.clone_count(), 1);
|
||||
assert_eq!(waker_handle.drop_count(), 1);
|
||||
assert_eq!(waker_handle.wake_count(), 1);
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn poll_with_different_wakers() {
|
||||
loom::model(|| {
|
||||
let (sender, mut receiver) = oneshot::channel::<u128>();
|
||||
|
||||
let (waker1, waker_handle1) = helpers::waker::waker();
|
||||
let mut context1 = task::Context::from_waker(&waker1);
|
||||
|
||||
assert_eq!(Pin::new(&mut receiver).poll(&mut context1), Poll::Pending);
|
||||
assert_eq!(waker_handle1.clone_count(), 1);
|
||||
assert_eq!(waker_handle1.drop_count(), 0);
|
||||
assert_eq!(waker_handle1.wake_count(), 0);
|
||||
|
||||
let (waker2, waker_handle2) = helpers::waker::waker();
|
||||
let mut context2 = task::Context::from_waker(&waker2);
|
||||
|
||||
assert_eq!(Pin::new(&mut receiver).poll(&mut context2), Poll::Pending);
|
||||
assert_eq!(waker_handle1.clone_count(), 1);
|
||||
assert_eq!(waker_handle1.drop_count(), 1);
|
||||
assert_eq!(waker_handle1.wake_count(), 0);
|
||||
|
||||
assert_eq!(waker_handle2.clone_count(), 1);
|
||||
assert_eq!(waker_handle2.drop_count(), 0);
|
||||
assert_eq!(waker_handle2.wake_count(), 0);
|
||||
|
||||
// Sending should cause the waker from the latest poll to be woken up
|
||||
sender.send(1234).unwrap();
|
||||
assert_eq!(waker_handle1.clone_count(), 1);
|
||||
assert_eq!(waker_handle1.drop_count(), 1);
|
||||
assert_eq!(waker_handle1.wake_count(), 0);
|
||||
|
||||
assert_eq!(waker_handle2.clone_count(), 1);
|
||||
assert_eq!(waker_handle2.drop_count(), 1);
|
||||
assert_eq!(waker_handle2.wake_count(), 1);
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn poll_then_try_recv() {
|
||||
loom::model(|| {
|
||||
let (_sender, mut receiver) = oneshot::channel::<u128>();
|
||||
|
||||
let (waker, waker_handle) = helpers::waker::waker();
|
||||
let mut context = task::Context::from_waker(&waker);
|
||||
|
||||
assert_eq!(Pin::new(&mut receiver).poll(&mut context), Poll::Pending);
|
||||
assert_eq!(waker_handle.clone_count(), 1);
|
||||
assert_eq!(waker_handle.drop_count(), 0);
|
||||
assert_eq!(waker_handle.wake_count(), 0);
|
||||
|
||||
assert_eq!(receiver.try_recv(), Err(TryRecvError::Empty));
|
||||
|
||||
assert_eq!(Pin::new(&mut receiver).poll(&mut context), Poll::Pending);
|
||||
assert_eq!(waker_handle.clone_count(), 2);
|
||||
assert_eq!(waker_handle.drop_count(), 1);
|
||||
assert_eq!(waker_handle.wake_count(), 0);
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn poll_then_try_recv_while_sending() {
|
||||
loom::model(|| {
|
||||
let (sender, mut receiver) = oneshot::channel::<u128>();
|
||||
|
||||
let (waker, waker_handle) = helpers::waker::waker();
|
||||
let mut context = task::Context::from_waker(&waker);
|
||||
|
||||
assert_eq!(Pin::new(&mut receiver).poll(&mut context), Poll::Pending);
|
||||
assert_eq!(waker_handle.clone_count(), 1);
|
||||
assert_eq!(waker_handle.drop_count(), 0);
|
||||
assert_eq!(waker_handle.wake_count(), 0);
|
||||
|
||||
let t = thread::spawn(move || {
|
||||
sender.send(1234).unwrap();
|
||||
});
|
||||
|
||||
let msg = loop {
|
||||
match receiver.try_recv() {
|
||||
Ok(msg) => break msg,
|
||||
Err(TryRecvError::Empty) => hint::spin_loop(),
|
||||
Err(TryRecvError::Disconnected) => panic!("Should not be disconnected"),
|
||||
}
|
||||
};
|
||||
assert_eq!(msg, 1234);
|
||||
assert_eq!(waker_handle.clone_count(), 1);
|
||||
assert_eq!(waker_handle.drop_count(), 1);
|
||||
assert_eq!(waker_handle.wake_count(), 1);
|
||||
|
||||
t.join().unwrap();
|
||||
})
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
#![cfg(not(loom))]
|
||||
|
||||
use oneshot::{channel, Receiver, Sender};
|
||||
|
||||
#[test]
|
||||
fn test_raw_sender() {
|
||||
let (sender, receiver) = channel::<u32>();
|
||||
let raw = sender.into_raw();
|
||||
let recreated = unsafe { Sender::<u32>::from_raw(raw) };
|
||||
recreated
|
||||
.send(100)
|
||||
.unwrap_or_else(|e| panic!("error sending after into_raw/from_raw roundtrip: {e}"));
|
||||
assert_eq!(receiver.try_recv(), Ok(100))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_receiver() {
|
||||
let (sender, receiver) = channel::<u32>();
|
||||
let raw = receiver.into_raw();
|
||||
sender.send(100).unwrap();
|
||||
let recreated = unsafe { Receiver::<u32>::from_raw(raw) };
|
||||
assert_eq!(
|
||||
recreated
|
||||
.try_recv()
|
||||
.unwrap_or_else(|e| panic!("error receiving after into_raw/from_raw roundtrip: {e}")),
|
||||
100
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_sender_and_receiver() {
|
||||
let (sender, receiver) = channel::<u32>();
|
||||
let raw_receiver = receiver.into_raw();
|
||||
let raw_sender = sender.into_raw();
|
||||
|
||||
let recreated_sender = unsafe { Sender::<u32>::from_raw(raw_sender) };
|
||||
recreated_sender.send(100).unwrap();
|
||||
|
||||
let recreated_receiver = unsafe { Receiver::<u32>::from_raw(raw_receiver) };
|
||||
assert_eq!(
|
||||
recreated_receiver
|
||||
.try_recv()
|
||||
.unwrap_or_else(|e| panic!("error receiving after into_raw/from_raw roundtrip: {e}")),
|
||||
100
|
||||
)
|
||||
}
|
|
@ -1,343 +0,0 @@
|
|||
use core::mem;
|
||||
use oneshot::TryRecvError;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use oneshot::{RecvError, RecvTimeoutError};
|
||||
#[cfg(feature = "std")]
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod thread {
|
||||
#[cfg(loom)]
|
||||
pub use loom::thread::spawn;
|
||||
#[cfg(not(loom))]
|
||||
pub use std::thread::{sleep, spawn};
|
||||
|
||||
#[cfg(loom)]
|
||||
pub fn sleep(_timeout: core::time::Duration) {
|
||||
loom::thread::yield_now()
|
||||
}
|
||||
}
|
||||
|
||||
mod helpers;
|
||||
use helpers::{maybe_loom_model, DropCounter};
|
||||
|
||||
#[test]
|
||||
fn send_before_try_recv() {
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
assert!(sender.send(19i128).is_ok());
|
||||
|
||||
assert_eq!(receiver.try_recv(), Ok(19i128));
|
||||
assert_eq!(receiver.try_recv(), Err(TryRecvError::Disconnected));
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
assert_eq!(receiver.recv_ref(), Err(RecvError));
|
||||
assert!(receiver.recv_timeout(Duration::from_secs(1)).is_err());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn send_before_recv() {
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel::<()>();
|
||||
assert!(sender.send(()).is_ok());
|
||||
assert_eq!(receiver.recv(), Ok(()));
|
||||
});
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel::<u8>();
|
||||
assert!(sender.send(19).is_ok());
|
||||
assert_eq!(receiver.recv(), Ok(19));
|
||||
});
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel::<u64>();
|
||||
assert!(sender.send(21).is_ok());
|
||||
assert_eq!(receiver.recv(), Ok(21));
|
||||
});
|
||||
// FIXME: This test does not work with loom. There is something that happens after the
|
||||
// channel object becomes larger than ~500 bytes and that makes an atomic read from the state
|
||||
// result in "signal: 10, SIGBUS: access to undefined memory"
|
||||
#[cfg(not(loom))]
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel::<[u8; 4096]>();
|
||||
assert!(sender.send([0b10101010; 4096]).is_ok());
|
||||
assert!(receiver.recv().unwrap()[..] == [0b10101010; 4096][..]);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn send_before_recv_ref() {
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
assert!(sender.send(19i128).is_ok());
|
||||
|
||||
assert_eq!(receiver.recv_ref(), Ok(19i128));
|
||||
assert_eq!(receiver.recv_ref(), Err(RecvError));
|
||||
assert_eq!(receiver.try_recv(), Err(TryRecvError::Disconnected));
|
||||
assert!(receiver.recv_timeout(Duration::from_secs(1)).is_err());
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn send_before_recv_timeout() {
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
assert!(sender.send(19i128).is_ok());
|
||||
|
||||
let start = Instant::now();
|
||||
let timeout = Duration::from_secs(1);
|
||||
assert_eq!(receiver.recv_timeout(timeout), Ok(19i128));
|
||||
assert!(start.elapsed() < Duration::from_millis(100));
|
||||
|
||||
assert!(receiver.recv_timeout(timeout).is_err());
|
||||
assert!(receiver.try_recv().is_err());
|
||||
assert!(receiver.recv().is_err());
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_then_drop_receiver() {
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
assert!(sender.send(19i128).is_ok());
|
||||
mem::drop(receiver);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_with_dropped_receiver() {
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
mem::drop(receiver);
|
||||
let send_error = sender.send(5u128).unwrap_err();
|
||||
assert_eq!(*send_error.as_inner(), 5);
|
||||
assert_eq!(send_error.into_inner(), 5);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_recv_with_dropped_sender() {
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
mem::drop(sender);
|
||||
receiver.try_recv().unwrap_err();
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn recv_with_dropped_sender() {
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
mem::drop(sender);
|
||||
receiver.recv().unwrap_err();
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn recv_before_send() {
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let t = thread::spawn(move || {
|
||||
thread::sleep(Duration::from_millis(2));
|
||||
sender.send(9u128).unwrap();
|
||||
});
|
||||
assert_eq!(receiver.recv(), Ok(9));
|
||||
t.join().unwrap();
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn recv_timeout_before_send() {
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let t = thread::spawn(move || {
|
||||
thread::sleep(Duration::from_millis(2));
|
||||
sender.send(9u128).unwrap();
|
||||
});
|
||||
assert_eq!(receiver.recv_timeout(Duration::from_secs(1)), Ok(9));
|
||||
t.join().unwrap();
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn recv_before_send_then_drop_sender() {
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
let t = thread::spawn(move || {
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
mem::drop(sender);
|
||||
});
|
||||
assert!(receiver.recv().is_err());
|
||||
t.join().unwrap();
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn recv_timeout_before_send_then_drop_sender() {
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
let t = thread::spawn(move || {
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
mem::drop(sender);
|
||||
});
|
||||
assert!(receiver.recv_timeout(Duration::from_secs(1)).is_err());
|
||||
t.join().unwrap();
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_recv() {
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
assert_eq!(receiver.try_recv(), Err(TryRecvError::Empty));
|
||||
mem::drop(sender)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn try_recv_then_drop_receiver() {
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel::<u128>();
|
||||
let t1 = thread::spawn(move || {
|
||||
let _ = sender.send(42);
|
||||
});
|
||||
let t2 = thread::spawn(move || {
|
||||
assert!(matches!(
|
||||
receiver.try_recv(),
|
||||
Ok(42) | Err(TryRecvError::Empty)
|
||||
));
|
||||
mem::drop(receiver);
|
||||
});
|
||||
t1.join().unwrap();
|
||||
t2.join().unwrap();
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn recv_deadline_and_timeout_no_time() {
|
||||
maybe_loom_model(|| {
|
||||
let (_sender, receiver) = oneshot::channel::<u128>();
|
||||
|
||||
let start = Instant::now();
|
||||
assert_eq!(
|
||||
receiver.recv_deadline(start),
|
||||
Err(RecvTimeoutError::Timeout)
|
||||
);
|
||||
assert!(start.elapsed() < Duration::from_millis(200));
|
||||
|
||||
let start = Instant::now();
|
||||
assert_eq!(
|
||||
receiver.recv_timeout(Duration::from_millis(0)),
|
||||
Err(RecvTimeoutError::Timeout)
|
||||
);
|
||||
assert!(start.elapsed() < Duration::from_millis(200));
|
||||
})
|
||||
}
|
||||
|
||||
// This test doesn't give meaningful results when run with oneshot_test_delay and loom
|
||||
#[cfg(all(feature = "std", not(all(oneshot_test_delay, loom))))]
|
||||
#[test]
|
||||
fn recv_deadline_time_should_elapse() {
|
||||
maybe_loom_model(|| {
|
||||
let (_sender, receiver) = oneshot::channel::<u128>();
|
||||
|
||||
let start = Instant::now();
|
||||
#[cfg(not(loom))]
|
||||
let timeout = Duration::from_millis(100);
|
||||
#[cfg(loom)]
|
||||
let timeout = Duration::from_millis(1);
|
||||
assert_eq!(
|
||||
receiver.recv_deadline(start + timeout),
|
||||
Err(RecvTimeoutError::Timeout)
|
||||
);
|
||||
assert!(start.elapsed() > timeout);
|
||||
assert!(start.elapsed() < timeout * 3);
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "std", not(all(oneshot_test_delay, loom))))]
|
||||
#[test]
|
||||
fn recv_timeout_time_should_elapse() {
|
||||
maybe_loom_model(|| {
|
||||
let (_sender, receiver) = oneshot::channel::<u128>();
|
||||
|
||||
let start = Instant::now();
|
||||
#[cfg(not(loom))]
|
||||
let timeout = Duration::from_millis(100);
|
||||
#[cfg(loom)]
|
||||
let timeout = Duration::from_millis(1);
|
||||
|
||||
assert_eq!(
|
||||
receiver.recv_timeout(timeout),
|
||||
Err(RecvTimeoutError::Timeout)
|
||||
);
|
||||
assert!(start.elapsed() > timeout);
|
||||
assert!(start.elapsed() < timeout * 3);
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(loom))]
|
||||
#[test]
|
||||
fn non_send_type_can_be_used_on_same_thread() {
|
||||
use std::ptr;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
struct NotSend(*mut ());
|
||||
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
sender.send(NotSend(ptr::null_mut())).unwrap();
|
||||
let reply = receiver.try_recv().unwrap();
|
||||
assert_eq!(reply, NotSend(ptr::null_mut()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn message_in_channel_dropped_on_receiver_drop() {
|
||||
maybe_loom_model(|| {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let (message, counter) = DropCounter::new(());
|
||||
assert_eq!(counter.count(), 0);
|
||||
sender.send(message).unwrap();
|
||||
assert_eq!(counter.count(), 0);
|
||||
mem::drop(receiver);
|
||||
assert_eq!(counter.count(), 1);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_error_drops_message_correctly() {
|
||||
maybe_loom_model(|| {
|
||||
let (sender, _) = oneshot::channel();
|
||||
let (message, counter) = DropCounter::new(());
|
||||
|
||||
let send_error = sender.send(message).unwrap_err();
|
||||
assert_eq!(counter.count(), 0);
|
||||
mem::drop(send_error);
|
||||
assert_eq!(counter.count(), 1);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_error_drops_message_correctly_on_into_inner() {
|
||||
maybe_loom_model(|| {
|
||||
let (sender, _) = oneshot::channel();
|
||||
let (message, counter) = DropCounter::new(());
|
||||
|
||||
let send_error = sender.send(message).unwrap_err();
|
||||
assert_eq!(counter.count(), 0);
|
||||
let message = send_error.into_inner();
|
||||
assert_eq!(counter.count(), 0);
|
||||
mem::drop(message);
|
||||
assert_eq!(counter.count(), 1);
|
||||
});
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
{"files":{"Cargo.toml":"7f8e0b5d66e9c5621c5fb57d4b16b801a24061e37ee337e06f8a004e6895a8dc","LICENSE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","src/lib.rs":"ef4f143f99e9ef4f17dab02e1b80ed3ac484ae58e0bb64164920720e0ca9425f","src/shared.rs":"e0c98ea10f78491f567e2a18bcb41b3f0ae01ce587d8b3a16ce0dc1097919109","src/tables.rs":"1821b437dfb31164ce8180af3937ca42270f1edf963a2d2e41cbaaf999553c94"},"package":"3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"}
|
|
@ -1,32 +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 are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.56"
|
||||
name = "unicode-linebreak"
|
||||
version = "0.1.5"
|
||||
authors = ["Axel Forsman <axelsfor@gmail.com>"]
|
||||
include = [
|
||||
"src/**/*",
|
||||
"LICENSE",
|
||||
]
|
||||
description = "Implementation of the Unicode Line Breaking Algorithm"
|
||||
homepage = "https://github.com/axelf4/unicode-linebreak"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"unicode",
|
||||
"text",
|
||||
"layout",
|
||||
]
|
||||
categories = ["internationalization"]
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/axelf4/unicode-linebreak"
|
|
@ -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,160 +0,0 @@
|
|||
//! Implementation of the Line Breaking Algorithm described in [Unicode Standard Annex #14][UAX14].
|
||||
//!
|
||||
//! Given an input text, locates "line break opportunities", or positions appropriate for wrapping
|
||||
//! lines when displaying text.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! use unicode_linebreak::{linebreaks, BreakOpportunity::{Mandatory, Allowed}};
|
||||
//!
|
||||
//! let text = "a b \nc";
|
||||
//! assert!(linebreaks(text).eq([
|
||||
//! (2, Allowed), // May break after first space
|
||||
//! (5, Mandatory), // Must break after line feed
|
||||
//! (6, Mandatory) // Must break at end of text, so that there always is at least one LB
|
||||
//! ]));
|
||||
//! ```
|
||||
//!
|
||||
//! [UAX14]: https://www.unicode.org/reports/tr14/
|
||||
|
||||
#![no_std]
|
||||
#![deny(missing_docs, missing_debug_implementations)]
|
||||
|
||||
use core::iter::once;
|
||||
|
||||
/// The [Unicode version](https://www.unicode.org/versions/) conformed to.
|
||||
pub const UNICODE_VERSION: (u8, u8, u8) = (15, 0, 0);
|
||||
|
||||
include!("shared.rs");
|
||||
include!("tables.rs");
|
||||
|
||||
/// Returns the line break property of the specified code point.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use unicode_linebreak::{BreakClass, break_property};
|
||||
/// assert_eq!(break_property(0x2CF3), BreakClass::Alphabetic);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn break_property(codepoint: u32) -> BreakClass {
|
||||
const BMP_INDEX_LENGTH: u32 = BMP_LIMIT >> BMP_SHIFT;
|
||||
const OMITTED_BMP_INDEX_1_LENGTH: u32 = BMP_LIMIT >> SHIFT_1;
|
||||
|
||||
let data_pos = if codepoint < BMP_LIMIT {
|
||||
let i = codepoint >> BMP_SHIFT;
|
||||
BREAK_PROP_TRIE_INDEX[i as usize] + (codepoint & (BMP_DATA_BLOCK_LENGTH - 1)) as u16
|
||||
} else if codepoint < BREAK_PROP_TRIE_HIGH_START {
|
||||
let i1 = codepoint >> SHIFT_1;
|
||||
let i2 = BREAK_PROP_TRIE_INDEX
|
||||
[(i1 + BMP_INDEX_LENGTH - OMITTED_BMP_INDEX_1_LENGTH) as usize]
|
||||
+ ((codepoint >> SHIFT_2) & (INDEX_2_BLOCK_LENGTH - 1)) as u16;
|
||||
let i3_block = BREAK_PROP_TRIE_INDEX[i2 as usize];
|
||||
let i3_pos = ((codepoint >> SHIFT_3) & (INDEX_3_BLOCK_LENGTH - 1)) as u16;
|
||||
|
||||
debug_assert!(i3_block & 0x8000 == 0, "18-bit indices are unexpected");
|
||||
let data_block = BREAK_PROP_TRIE_INDEX[(i3_block + i3_pos) as usize];
|
||||
data_block + (codepoint & (SMALL_DATA_BLOCK_LENGTH - 1)) as u16
|
||||
} else {
|
||||
return XX;
|
||||
};
|
||||
BREAK_PROP_TRIE_DATA[data_pos as usize]
|
||||
}
|
||||
|
||||
/// Break opportunity type.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum BreakOpportunity {
|
||||
/// A line must break at this spot.
|
||||
Mandatory,
|
||||
/// A line is allowed to end at this spot.
|
||||
Allowed,
|
||||
}
|
||||
|
||||
/// Returns an iterator over line break opportunities in the specified string.
|
||||
///
|
||||
/// Break opportunities are given as tuples of the byte index of the character succeeding the break
|
||||
/// and the type.
|
||||
///
|
||||
/// Uses the default Line Breaking Algorithm with the tailoring that Complex-Context Dependent
|
||||
/// (SA) characters get resolved to Ordinary Alphabetic and Symbol Characters (AL) regardless of
|
||||
/// General_Category.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use unicode_linebreak::{linebreaks, BreakOpportunity::{Mandatory, Allowed}};
|
||||
/// assert!(linebreaks("Hello world!").eq(vec![(6, Allowed), (12, Mandatory)]));
|
||||
/// ```
|
||||
pub fn linebreaks(s: &str) -> impl Iterator<Item = (usize, BreakOpportunity)> + Clone + '_ {
|
||||
use BreakOpportunity::{Allowed, Mandatory};
|
||||
|
||||
s.char_indices()
|
||||
.map(|(i, c)| (i, break_property(c as u32) as u8))
|
||||
.chain(once((s.len(), eot)))
|
||||
.scan((sot, false), |state, (i, cls)| {
|
||||
// ZWJ is handled outside the table to reduce its size
|
||||
let val = PAIR_TABLE[state.0 as usize][cls as usize];
|
||||
let is_mandatory = val & MANDATORY_BREAK_BIT != 0;
|
||||
let is_break = val & ALLOWED_BREAK_BIT != 0 && (!state.1 || is_mandatory);
|
||||
*state = (
|
||||
val & !(ALLOWED_BREAK_BIT | MANDATORY_BREAK_BIT),
|
||||
cls == BreakClass::ZeroWidthJoiner as u8,
|
||||
);
|
||||
|
||||
Some((i, is_break, is_mandatory))
|
||||
})
|
||||
.filter_map(|(i, is_break, is_mandatory)| {
|
||||
if is_break {
|
||||
Some((i, if is_mandatory { Mandatory } else { Allowed }))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Divides the string at the last index where further breaks do not depend on prior context.
|
||||
///
|
||||
/// The trivial index at `eot` is excluded.
|
||||
///
|
||||
/// A common optimization is to determine only the nearest line break opportunity before the first
|
||||
/// character that would cause the line to become overfull, requiring backward traversal, of which
|
||||
/// there are two approaches:
|
||||
///
|
||||
/// * Cache breaks from forward traversals
|
||||
/// * Step backward and with `split_at_safe` find a pos to safely search forward from, repeatedly
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use unicode_linebreak::{linebreaks, split_at_safe};
|
||||
/// let s = "Not allowed to break within em dashes: — —";
|
||||
/// let (prev, safe) = split_at_safe(s);
|
||||
/// let n = prev.len();
|
||||
/// assert!(linebreaks(safe).eq(linebreaks(s).filter_map(|(i, x)| i.checked_sub(n).map(|i| (i, x)))));
|
||||
/// ```
|
||||
pub fn split_at_safe(s: &str) -> (&str, &str) {
|
||||
let mut chars = s.char_indices().rev().scan(None, |state, (i, c)| {
|
||||
let cls = break_property(c as u32);
|
||||
let is_safe_pair = state
|
||||
.replace(cls)
|
||||
.map_or(false, |prev| is_safe_pair(cls, prev)); // Reversed since iterating backwards
|
||||
Some((i, is_safe_pair))
|
||||
});
|
||||
chars.find(|&(_, is_safe_pair)| is_safe_pair);
|
||||
// Include preceding char for `linebreaks` to pick up break before match (disallowed after sot)
|
||||
s.split_at(chars.next().map_or(0, |(i, _)| i))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(break_property(0xA), BreakClass::LineFeed);
|
||||
assert_eq!(break_property(0xDB80), BreakClass::Surrogate);
|
||||
assert_eq!(break_property(0xe01ef), BreakClass::CombiningMark);
|
||||
assert_eq!(break_property(0x10ffff), BreakClass::Unknown);
|
||||
}
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
/// Unicode line breaking class.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
#[repr(u8)]
|
||||
pub enum BreakClass {
|
||||
// Non-tailorable
|
||||
/// Cause a line break (after)
|
||||
Mandatory,
|
||||
/// Cause a line break (after), except between CR and LF
|
||||
CarriageReturn,
|
||||
/// Cause a line break (after)
|
||||
LineFeed,
|
||||
/// Prohibit a line break between the character and the preceding character
|
||||
CombiningMark,
|
||||
/// Cause a line break (after)
|
||||
NextLine,
|
||||
/// Do not occur in well-formed text
|
||||
Surrogate,
|
||||
/// Prohibit line breaks before and after
|
||||
WordJoiner,
|
||||
/// Provide a break opportunity
|
||||
ZeroWidthSpace,
|
||||
/// Prohibit line breaks before and after
|
||||
NonBreakingGlue,
|
||||
/// Enable indirect line breaks
|
||||
Space,
|
||||
/// Prohibit line breaks within joiner sequences
|
||||
ZeroWidthJoiner,
|
||||
// Break opportunities
|
||||
/// Provide a line break opportunity before and after the character
|
||||
BeforeAndAfter,
|
||||
/// Generally provide a line break opportunity after the character
|
||||
After,
|
||||
/// Generally provide a line break opportunity before the character
|
||||
Before,
|
||||
/// Provide a line break opportunity after the character, except in numeric context
|
||||
Hyphen,
|
||||
/// Provide a line break opportunity contingent on additional information
|
||||
Contingent,
|
||||
// Characters prohibiting certain breaks
|
||||
/// Prohibit line breaks before
|
||||
ClosePunctuation,
|
||||
/// Prohibit line breaks before
|
||||
CloseParenthesis,
|
||||
/// Prohibit line breaks before
|
||||
Exclamation,
|
||||
/// Allow only indirect line breaks between pairs
|
||||
Inseparable,
|
||||
/// Allow only indirect line breaks before
|
||||
NonStarter,
|
||||
/// Prohibit line breaks after
|
||||
OpenPunctuation,
|
||||
/// Act like they are both opening and closing
|
||||
Quotation,
|
||||
// Numeric context
|
||||
/// Prevent breaks after any and before numeric
|
||||
InfixSeparator,
|
||||
/// Form numeric expressions for line breaking purposes
|
||||
Numeric,
|
||||
/// Do not break following a numeric expression
|
||||
Postfix,
|
||||
/// Do not break in front of a numeric expression
|
||||
Prefix,
|
||||
/// Prevent a break before, and allow a break after
|
||||
Symbol,
|
||||
// Other characters
|
||||
/// Act like AL when the resolved EAW is N; otherwise, act as ID
|
||||
Ambiguous,
|
||||
/// Are alphabetic characters or symbols that are used with alphabetic characters
|
||||
Alphabetic,
|
||||
/// Treat as NS or ID for strict or normal breaking.
|
||||
ConditionalJapaneseStarter,
|
||||
/// Do not break from following Emoji Modifier
|
||||
EmojiBase,
|
||||
/// Do not break from preceding Emoji Base
|
||||
EmojiModifier,
|
||||
/// Form Korean syllable blocks
|
||||
HangulLvSyllable,
|
||||
/// Form Korean syllable blocks
|
||||
HangulLvtSyllable,
|
||||
/// Do not break around a following hyphen; otherwise act as Alphabetic
|
||||
HebrewLetter,
|
||||
/// Break before or after, except in some numeric context
|
||||
Ideographic,
|
||||
/// Form Korean syllable blocks
|
||||
HangulLJamo,
|
||||
/// Form Korean syllable blocks
|
||||
HangulVJamo,
|
||||
/// Form Korean syllable blocks
|
||||
HangulTJamo,
|
||||
/// Keep pairs together. For pairs, break before and after other classes
|
||||
RegionalIndicator,
|
||||
/// Provide a line break opportunity contingent on additional, language-specific context analysis
|
||||
ComplexContext,
|
||||
/// Have as yet unknown line breaking behavior or unassigned code positions
|
||||
Unknown,
|
||||
}
|
||||
|
||||
use BreakClass::{
|
||||
After as BA, Alphabetic as AL, Ambiguous as AI, Before as BB, BeforeAndAfter as B2,
|
||||
CarriageReturn as CR, CloseParenthesis as CP, ClosePunctuation as CL, CombiningMark as CM,
|
||||
ComplexContext as SA, ConditionalJapaneseStarter as CJ, Contingent as CB, EmojiBase as EB,
|
||||
EmojiModifier as EM, Exclamation as EX, HangulLJamo as JL, HangulLvSyllable as H2,
|
||||
HangulLvtSyllable as H3, HangulTJamo as JT, HangulVJamo as JV, HebrewLetter as HL,
|
||||
Hyphen as HY, Ideographic as ID, InfixSeparator as IS, Inseparable as IN, LineFeed as LF,
|
||||
Mandatory as BK, NextLine as NL, NonBreakingGlue as GL, NonStarter as NS, Numeric as NU,
|
||||
OpenPunctuation as OP, Postfix as PO, Prefix as PR, Quotation as QU, RegionalIndicator as RI,
|
||||
Space as SP, Surrogate as SG, Symbol as SY, Unknown as XX, WordJoiner as WJ,
|
||||
ZeroWidthJoiner as ZWJ, ZeroWidthSpace as ZW,
|
||||
};
|
||||
|
||||
/// Ceiling for code points in the Basic Multilingual Place (BMP).
|
||||
const BMP_LIMIT: u32 = 0x10000;
|
||||
|
||||
/// Shift size for getting index-3 table offset.
|
||||
const SHIFT_3: u32 = 4;
|
||||
/// Shift size for getting index-2 table offset.
|
||||
const SHIFT_2: u32 = 5 + SHIFT_3;
|
||||
/// Shift size for getting index-1 table offset.
|
||||
const SHIFT_1: u32 = 5 + SHIFT_2;
|
||||
/// Shift size for getting BMP block start.
|
||||
const BMP_SHIFT: u32 = 6;
|
||||
|
||||
const INDEX_2_BLOCK_LENGTH: u32 = 1 << (SHIFT_1 - SHIFT_2);
|
||||
const INDEX_3_BLOCK_LENGTH: u32 = 1 << (SHIFT_2 - SHIFT_3);
|
||||
const SMALL_DATA_BLOCK_LENGTH: u32 = 1 << SHIFT_3;
|
||||
const BMP_DATA_BLOCK_LENGTH: u32 = 1 << BMP_SHIFT;
|
||||
|
||||
const ALLOWED_BREAK_BIT: u8 = 0x80;
|
||||
const MANDATORY_BREAK_BIT: u8 = 0x40;
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
const eot: u8 = 43;
|
||||
#[allow(non_upper_case_globals)]
|
||||
const sot: u8 = 44;
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"eb974d356d4da93a076434ff428c448f70e036a724bd9a0a7eae6b9ddff2346e","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","release.toml":"1aa1b131d4cc93b5eba8758a4401c70bc0d7fe5861e2ec147e9259fe7c0da472","src/cli.rs":"5c0b9bb93665f2f49f7e90335e65206887e26e96f2a533eb1203be27c9380c84","src/lib.rs":"422503d7cbac1360852287b1810c99663669625b9abf080a5fec22058bb73d8c","tests/ui/proc_macro_arc.rs":"fedc429603753e8ef953642a7295323ccb3f76fd3ae1ab181ad90c5eb88212bb","tests/ui/proc_macro_arc.stderr":"a24af227b907328c9cac6317ec9f43dbc45d7f7c77c603e5d72db7fa050e8b01","tests/ui/version_mismatch.rs":"16ea359e5853517ee0d0704c015ae8c825533109fbefd715130d0f4a51f15898","tests/ui/version_mismatch.stderr":"21dcb836253312ba8e3a0502cce6ff279818aaaadcea9628a41b196e0c8c94b6"},"package":"a5566fae48a5cb017005bf9cd622af5236b2a203a13fb548afde3506d3c68277"}
|
||||
{"files":{"Cargo.toml":"7c45cfa5f95f1db4ec3cb139f8f5166281f7893b21a4313ee4a4f4070bef1816","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","release.toml":"1aa1b131d4cc93b5eba8758a4401c70bc0d7fe5861e2ec147e9259fe7c0da472","src/cli.rs":"5c0b9bb93665f2f49f7e90335e65206887e26e96f2a533eb1203be27c9380c84","src/lib.rs":"422503d7cbac1360852287b1810c99663669625b9abf080a5fec22058bb73d8c","tests/ui/proc_macro_arc.rs":"fedc429603753e8ef953642a7295323ccb3f76fd3ae1ab181ad90c5eb88212bb","tests/ui/proc_macro_arc.stderr":"a24af227b907328c9cac6317ec9f43dbc45d7f7c77c603e5d72db7fa050e8b01","tests/ui/version_mismatch.rs":"16ea359e5853517ee0d0704c015ae8c825533109fbefd715130d0f4a51f15898","tests/ui/version_mismatch.stderr":"21dcb836253312ba8e3a0502cce6ff279818aaaadcea9628a41b196e0c8c94b6"},"package":"cb3a4c447c50fcda7bc5604a8588b7e1f37ffbfd8838a1516a290398efa7c6f0"}
|
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2021"
|
||||
name = "uniffi"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
|
||||
description = "a multi-language bindings generator for rust"
|
||||
homepage = "https://mozilla.github.io/uniffi-rs"
|
||||
|
@ -42,18 +42,18 @@ features = [
|
|||
optional = true
|
||||
|
||||
[dependencies.uniffi_bindgen]
|
||||
version = "=0.27.1"
|
||||
version = "=0.27.3"
|
||||
optional = true
|
||||
|
||||
[dependencies.uniffi_build]
|
||||
version = "=0.27.1"
|
||||
version = "=0.27.3"
|
||||
optional = true
|
||||
|
||||
[dependencies.uniffi_core]
|
||||
version = "=0.27.1"
|
||||
version = "=0.27.3"
|
||||
|
||||
[dependencies.uniffi_macros]
|
||||
version = "=0.27.1"
|
||||
version = "=0.27.3"
|
||||
|
||||
[dev-dependencies.trybuild]
|
||||
version = "1"
|
||||
|
@ -69,4 +69,8 @@ cli = [
|
|||
"dep:camino",
|
||||
]
|
||||
default = []
|
||||
scaffolding-ffi-buffer-fns = [
|
||||
"uniffi_core/scaffolding-ffi-buffer-fns",
|
||||
"uniffi_macros/scaffolding-ffi-buffer-fns",
|
||||
]
|
||||
tokio = ["uniffi_core/tokio"]
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2021"
|
||||
name = "uniffi_bindgen"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
|
||||
description = "a multi-language bindings generator for rust (codegen and cli tooling)"
|
||||
homepage = "https://mozilla.github.io/uniffi-rs"
|
||||
|
@ -72,15 +72,17 @@ features = ["derive"]
|
|||
|
||||
[dependencies.textwrap]
|
||||
version = "0.16"
|
||||
features = ["smawk"]
|
||||
default-features = false
|
||||
|
||||
[dependencies.toml]
|
||||
version = "0.5"
|
||||
|
||||
[dependencies.uniffi_meta]
|
||||
version = "=0.27.1"
|
||||
version = "=0.27.3"
|
||||
|
||||
[dependencies.uniffi_testing]
|
||||
version = "=0.27.1"
|
||||
version = "=0.27.3"
|
||||
|
||||
[dependencies.uniffi_udl]
|
||||
version = "=0.27.1"
|
||||
version = "=0.27.3"
|
||||
|
|
|
@ -218,6 +218,12 @@ impl FfiFunction {
|
|||
&self.name
|
||||
}
|
||||
|
||||
/// Name of the FFI buffer version of this function that's generated when the
|
||||
/// `scaffolding-ffi-buffer-fns` feature is enabled.
|
||||
pub fn ffi_buffer_fn_name(&self) -> String {
|
||||
uniffi_meta::ffi_buffer_symbol_name(&self.name)
|
||||
}
|
||||
|
||||
pub fn is_async(&self) -> bool {
|
||||
self.is_async
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"8fcf43ff5e6c1281a1ee5f9ed796b0f8115bd39ca9ce5b2d0c32e88d9eb2038f","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","src/lib.rs":"47ff3d1a18456164414af1c20cd5df129401e5257cc15552ecc39afed8970707"},"package":"45cba427aeb7b3a8b54830c4c915079a7a3c62608dd03dddba1d867a8a023eb4"}
|
||||
{"files":{"Cargo.toml":"a79595948b5661477a6fd0506fa0abae05d83d3f0a4c31f16c20c143f6236b42","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","src/lib.rs":"47ff3d1a18456164414af1c20cd5df129401e5257cc15552ecc39afed8970707"},"package":"1c59b65d59685ff3a10569287c6419f76487b4052ac52d5a0df38b2253d7f440"}
|
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2021"
|
||||
name = "uniffi_build"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
|
||||
description = "a multi-language bindings generator for rust (build script helpers)"
|
||||
homepage = "https://mozilla.github.io/uniffi-rs"
|
||||
|
@ -32,7 +32,7 @@ version = "1"
|
|||
version = "1.0.8"
|
||||
|
||||
[dependencies.uniffi_bindgen]
|
||||
version = "=0.27.1"
|
||||
version = "=0.27.3"
|
||||
default-features = false
|
||||
|
||||
[features]
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"da89504b9007c2a1ea0e498a2e8ec6baeb0ff7391363cd9007e383247637792c","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","src/lib.rs":"44d2e2c595b14d33d16c71dfe4ef42ad0b9e010a878ee2ec49c2e929d60275ba"},"package":"ae7e5a6c33b1dec3f255f57ec0b6af0f0b2bb3021868be1d5eec7a38e2905ebc"}
|
||||
{"files":{"Cargo.toml":"efec1e1624f962fd264a0003ac8d40311c4af50f69d7ed537119ca74c73255a0","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","src/lib.rs":"44d2e2c595b14d33d16c71dfe4ef42ad0b9e010a878ee2ec49c2e929d60275ba"},"package":"d5c400339a9d1d17be34257d0b407e91d64af335e5b4fa49f4bf28467fc8d635"}
|
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2021"
|
||||
name = "uniffi_checksum_derive"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
|
||||
description = "a multi-language bindings generator for rust (checksum custom derive)"
|
||||
homepage = "https://mozilla.github.io/uniffi-rs"
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"c8969fbc6e8f6694e260ab78c94f9b4195d61afb7836b4c130b542d3b91b9200","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","release.toml":"b150796411fc6ff90b481218cb50f8ac7c07f5845aebdb8e17877d47e55b05b9","src/ffi/callbackinterface.rs":"f0184cf76bd86abb2815d260a87f85bd7060f5373ac6ef6f71955ece2a5075af","src/ffi/ffidefault.rs":"0db83fbcbc274c4c0daf7fb27833400568839b77a3496155840734c511d801e0","src/ffi/foreignbytes.rs":"d2b46e1a6317aa64801b855e0d12af6bcdef118d8036603d11c3cdaf6f35fdfe","src/ffi/foreigncallbacks.rs":"2b820a34b78705f5debc302a25c64d515a4aa7b3bdade083f4c1cfa2803664ae","src/ffi/foreignfuture.rs":"c1d621e41ea6af0c1d3959b46af8567c3fdc4164e7a82d635fcbb1da2c0737ac","src/ffi/handle.rs":"91f91469a81cb19edebb8bba433df62658cc66f6b54d5dc8520eb5793a85abd9","src/ffi/mod.rs":"30eea545299747838bf11b0698cfb71cedd3ca04d8cfb703c53198fcc44045c1","src/ffi/rustbuffer.rs":"0e725347f916834b17156413f406d5ca6c064b2cbc7437b051fe6692ad72c2aa","src/ffi/rustcalls.rs":"51c6499871c7d5eb4f80cabc806f26dd1df3b1090a2419d0d967aa9c5299a0a6","src/ffi/rustfuture/future.rs":"426cd0ad3c8cf008a7052a7d89856b6c6d5053b94e24325f5666d0281a40ec7f","src/ffi/rustfuture/mod.rs":"44568267e591f5b37f77acfdd6e60ae55ce48ab0a17fd81af3aeb31baa3d53e6","src/ffi/rustfuture/scheduler.rs":"c6484fff14c04596df5f306f2090366435dcff92561d317fde1ea9c097a9576b","src/ffi/rustfuture/tests.rs":"211241fb484a3a103eb0418e7d295850ea021bcd583fa1488f5efc68f33d5ab8","src/ffi_converter_impls.rs":"397c813f2e765462d7a7be524e6ac75e813a91a8ffd11c7e7df05f853213f77b","src/ffi_converter_traits.rs":"24c8cf6ada9b2f63b265e62c0f9092d640e533d0d7234e9156f92c3d1902f430","src/lib.rs":"1f6a031bbb160dfe46455a8bc24596f63b1e478f45579bfff62a62f58900bee4","src/metadata.rs":"83e463c377c0f501e58ac4eb5cc47c433c1473cecd47305fa89283e736b48d96","src/panichook.rs":"9f49c7994a8e5489c1105c488bb3f8c5571bc5f813e7be90441eca15da5c9851"},"package":"0ea3eb5474d50fc149b7e4d86b9c5bd4a61dcc167f0683902bf18ae7bbb3deef"}
|
||||
{"files":{"Cargo.toml":"c2bc10be9bffda0a1b9ea884f39d6499fc5b4bc8acb32ec33842c67c8ad72305","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","release.toml":"b150796411fc6ff90b481218cb50f8ac7c07f5845aebdb8e17877d47e55b05b9","src/ffi/callbackinterface.rs":"f0184cf76bd86abb2815d260a87f85bd7060f5373ac6ef6f71955ece2a5075af","src/ffi/ffidefault.rs":"0db83fbcbc274c4c0daf7fb27833400568839b77a3496155840734c511d801e0","src/ffi/ffiserialize.rs":"d34312d09d8851c0fc356990d9f3a8a488ea9f6ab089901b1d0c42180ad06be4","src/ffi/foreignbytes.rs":"d2b46e1a6317aa64801b855e0d12af6bcdef118d8036603d11c3cdaf6f35fdfe","src/ffi/foreigncallbacks.rs":"2b820a34b78705f5debc302a25c64d515a4aa7b3bdade083f4c1cfa2803664ae","src/ffi/foreignfuture.rs":"673a7a44d27b88d5297dc6f2da507c9db4d22e6306d9ebc5439cba9c6720cbcb","src/ffi/handle.rs":"91f91469a81cb19edebb8bba433df62658cc66f6b54d5dc8520eb5793a85abd9","src/ffi/mod.rs":"e4d46229ccda04fa42496cb72b09d57936311a1ac1d82343293613e708644494","src/ffi/rustbuffer.rs":"9df75f156dc8ea9565ae320654cc8caab899e688e5414da4e4a43dfe74db9522","src/ffi/rustcalls.rs":"9754b01988983b47d8f0ef6d4e5675cee92ec4ddeb073236b9ccfcac2b12e3ca","src/ffi/rustfuture/future.rs":"426cd0ad3c8cf008a7052a7d89856b6c6d5053b94e24325f5666d0281a40ec7f","src/ffi/rustfuture/mod.rs":"44568267e591f5b37f77acfdd6e60ae55ce48ab0a17fd81af3aeb31baa3d53e6","src/ffi/rustfuture/scheduler.rs":"c6484fff14c04596df5f306f2090366435dcff92561d317fde1ea9c097a9576b","src/ffi/rustfuture/tests.rs":"211241fb484a3a103eb0418e7d295850ea021bcd583fa1488f5efc68f33d5ab8","src/ffi_converter_impls.rs":"397c813f2e765462d7a7be524e6ac75e813a91a8ffd11c7e7df05f853213f77b","src/ffi_converter_traits.rs":"24c8cf6ada9b2f63b265e62c0f9092d640e533d0d7234e9156f92c3d1902f430","src/lib.rs":"477a833a1e41b9e07f3a6f052c6b7f48d11930449ff22b5ff949c7eeaa3e80b9","src/metadata.rs":"83e463c377c0f501e58ac4eb5cc47c433c1473cecd47305fa89283e736b48d96","src/oneshot.rs":"8f1b7e87cc139d274cacef1a7ad6a9e9bf85423a140ad4e5b61e38be9c6e7bb6","src/panichook.rs":"9f49c7994a8e5489c1105c488bb3f8c5571bc5f813e7be90441eca15da5c9851"},"package":"a02e67ac9634b10da9e4aa63a29a7920b8f1395eafef1ea659b2dd76dda96906"}
|
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2021"
|
||||
name = "uniffi_core"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
|
||||
description = "a multi-language bindings generator for rust (runtime support code)"
|
||||
homepage = "https://mozilla.github.io/uniffi-rs"
|
||||
|
@ -44,11 +44,6 @@ version = "0.4"
|
|||
[dependencies.once_cell]
|
||||
version = "1.10.0"
|
||||
|
||||
[dependencies.oneshot]
|
||||
version = "0.1.6"
|
||||
features = ["async"]
|
||||
package = "oneshot-uniffi"
|
||||
|
||||
[dependencies.paste]
|
||||
version = "1.0"
|
||||
|
||||
|
@ -57,4 +52,5 @@ version = "1.1.0"
|
|||
|
||||
[features]
|
||||
default = []
|
||||
scaffolding-ffi-buffer-fns = []
|
||||
tokio = ["dep:async-compat"]
|
||||
|
|
|
@ -0,0 +1,352 @@
|
|||
/* 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/. */
|
||||
|
||||
use crate::{Handle, RustBuffer, RustCallStatus, RustCallStatusCode};
|
||||
use std::{mem::MaybeUninit, ptr::NonNull};
|
||||
|
||||
/// FFIBuffer element
|
||||
///
|
||||
/// This is the union of all possible primitive FFI types.
|
||||
/// Composite FFI types like `RustBuffer` and `RustCallStatus` are stored using multiple elements.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub union FfiBufferElement {
|
||||
pub u8: u8,
|
||||
pub i8: i8,
|
||||
pub u16: u16,
|
||||
pub i16: i16,
|
||||
pub u32: u32,
|
||||
pub i32: i32,
|
||||
pub u64: u64,
|
||||
pub i64: i64,
|
||||
pub float: std::ffi::c_float,
|
||||
pub double: std::ffi::c_double,
|
||||
pub ptr: *const std::ffi::c_void,
|
||||
}
|
||||
|
||||
impl Default for FfiBufferElement {
|
||||
fn default() -> Self {
|
||||
Self { u64: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize a FFI value to a buffer
|
||||
///
|
||||
/// This trait allows FFI types to be read from/written to FFIBufferElement slices.
|
||||
/// It's similar, to the [crate::Lift::read] and [crate::Lower::write] methods, but implemented on the FFI types rather than Rust types.
|
||||
/// It's useful to compare the two:
|
||||
///
|
||||
/// - [crate::Lift] and [crate::Lower] are implemented on Rust types like String and user-defined records.
|
||||
/// - [FfiSerialize] is implemented on the FFI types like RustBuffer, RustCallStatus, and vtable structs.
|
||||
/// - All 3 traits are implemented for simple cases where the FFI type and Rust type are the same, for example numeric types.
|
||||
/// - [FfiSerialize] uses FFIBuffer elements rather than u8 elements. Using a union eliminates the need to cast values and creates better alignment.
|
||||
/// - [FfiSerialize] uses a constant size to store each type.
|
||||
///
|
||||
/// [FfiSerialize] is used to generate alternate forms of the scaffolding functions that simplify work needed to implement the bindings on the other side.
|
||||
/// This is currently only used in the gecko-js bindings for Firefox, but could maybe be useful for other external bindings or even some of the builtin bindings like Python/Kotlin.
|
||||
///
|
||||
/// The FFI-buffer version of the scaffolding functions:
|
||||
/// - Input two pointers to ffi buffers, one to read arguments from and one to write the return value to.
|
||||
/// - Rather than inputting an out pointer for `RustCallStatus` it's written to the return buffer after the normal return value.
|
||||
///
|
||||
pub trait FfiSerialize: Sized {
|
||||
/// Number of elements required to store this FFI type
|
||||
const SIZE: usize;
|
||||
|
||||
/// Get a value from a ffi buffer
|
||||
///
|
||||
/// Note: `buf` should be thought of as `&[FFIBufferElement; Self::SIZE]`, but it can't be spelled out that way
|
||||
/// since Rust doesn't support that usage of const generics yet.
|
||||
fn get(buf: &[FfiBufferElement]) -> Self;
|
||||
|
||||
/// Put a value to a ffi buffer
|
||||
///
|
||||
/// Note: `buf` should be thought of as `&[FFIBufferElement; Self::SIZE]`, but it can't be spelled out that way
|
||||
/// since Rust doesn't support that usage of const generics yet.
|
||||
fn put(buf: &mut [FfiBufferElement], value: Self);
|
||||
|
||||
/// Read a value from a ffi buffer ref and advance it
|
||||
///
|
||||
/// buf must have a length of at least `Self::Size`
|
||||
fn read(buf: &mut &[FfiBufferElement]) -> Self {
|
||||
let value = Self::get(buf);
|
||||
*buf = &buf[Self::SIZE..];
|
||||
value
|
||||
}
|
||||
|
||||
/// Write a value to a ffi buffer ref and advance it
|
||||
///
|
||||
/// buf must have a length of at least `Self::Size`
|
||||
fn write(buf: &mut &mut [FfiBufferElement], value: Self) {
|
||||
Self::put(buf, value);
|
||||
// Lifetime dance taken from `bytes::BufMut`
|
||||
let (_, new_buf) = core::mem::take(buf).split_at_mut(Self::SIZE);
|
||||
*buf = new_buf;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the FFI buffer size for list of types
|
||||
#[macro_export]
|
||||
macro_rules! ffi_buffer_size {
|
||||
($($T:ty),* $(,)?) => {
|
||||
(
|
||||
0
|
||||
$(
|
||||
+ <$T as $crate::FfiSerialize>::SIZE
|
||||
)*
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_ffi_serialize_simple_cases {
|
||||
($(($name: ident, $T:ty)),* $(,)?) => {
|
||||
$(
|
||||
impl FfiSerialize for $T {
|
||||
const SIZE: usize = 1;
|
||||
|
||||
fn get(buf: &[FfiBufferElement]) -> Self {
|
||||
// Safety: the foreign bindings are responsible for sending us the correct data.
|
||||
unsafe { buf[0].$name }
|
||||
}
|
||||
|
||||
fn put(buf: &mut[FfiBufferElement], value: Self) {
|
||||
buf[0].$name = value
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
define_ffi_serialize_simple_cases! {
|
||||
(i8, i8),
|
||||
(u8, u8),
|
||||
(i16, i16),
|
||||
(u16, u16),
|
||||
(i32, i32),
|
||||
(u32, u32),
|
||||
(i64, i64),
|
||||
(u64, u64),
|
||||
(ptr, *const std::ffi::c_void),
|
||||
}
|
||||
|
||||
impl FfiSerialize for f32 {
|
||||
const SIZE: usize = 1;
|
||||
|
||||
fn get(buf: &[FfiBufferElement]) -> Self {
|
||||
// Safety: the foreign bindings are responsible for sending us the correct data.
|
||||
unsafe { buf[0].float as Self }
|
||||
}
|
||||
|
||||
fn put(buf: &mut [FfiBufferElement], value: Self) {
|
||||
// Use a cast since it's theoretically possible for float to not be f32 on some systems.
|
||||
buf[0].float = value as std::ffi::c_float;
|
||||
}
|
||||
}
|
||||
|
||||
impl FfiSerialize for f64 {
|
||||
const SIZE: usize = 1;
|
||||
|
||||
fn get(buf: &[FfiBufferElement]) -> Self {
|
||||
// Safety: the foreign bindings are responsible for sending us the correct data.
|
||||
unsafe { buf[0].double as Self }
|
||||
}
|
||||
|
||||
fn put(buf: &mut [FfiBufferElement], value: Self) {
|
||||
// Use a cast since it's theoretically possible for double to not be f64 on some systems.
|
||||
buf[0].double = value as std::ffi::c_double;
|
||||
}
|
||||
}
|
||||
|
||||
impl FfiSerialize for bool {
|
||||
const SIZE: usize = 1;
|
||||
|
||||
fn get(buf: &[FfiBufferElement]) -> Self {
|
||||
// Safety: the foreign bindings are responsible for sending us the correct data.
|
||||
unsafe { buf[0].i8 == 1 }
|
||||
}
|
||||
|
||||
fn put(buf: &mut [FfiBufferElement], value: Self) {
|
||||
buf[0].i8 = if value { 1 } else { 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl FfiSerialize for () {
|
||||
const SIZE: usize = 0;
|
||||
|
||||
fn get(_buf: &[FfiBufferElement]) -> Self {}
|
||||
|
||||
fn put(_buf: &mut [FfiBufferElement], _value: Self) {}
|
||||
}
|
||||
|
||||
impl<T> FfiSerialize for NonNull<T> {
|
||||
const SIZE: usize = 1;
|
||||
|
||||
fn get(buf: &[FfiBufferElement]) -> Self {
|
||||
// Safety: this relies on the foreign code passing us valid pointers
|
||||
unsafe { Self::new_unchecked(buf[0].ptr as *mut T) }
|
||||
}
|
||||
|
||||
fn put(buf: &mut [FfiBufferElement], value: Self) {
|
||||
buf[0].ptr = value.as_ptr() as *const std::ffi::c_void
|
||||
}
|
||||
}
|
||||
|
||||
impl FfiSerialize for Handle {
|
||||
const SIZE: usize = 1;
|
||||
|
||||
fn get(buf: &[FfiBufferElement]) -> Self {
|
||||
unsafe { Handle::from_raw_unchecked(buf[0].u64) }
|
||||
}
|
||||
|
||||
fn put(buf: &mut [FfiBufferElement], value: Self) {
|
||||
buf[0].u64 = value.as_raw()
|
||||
}
|
||||
}
|
||||
|
||||
impl FfiSerialize for RustBuffer {
|
||||
const SIZE: usize = 3;
|
||||
|
||||
fn get(buf: &[FfiBufferElement]) -> Self {
|
||||
// Safety: the foreign bindings are responsible for sending us the correct data.
|
||||
let (capacity, len, data) = unsafe { (buf[0].u64, buf[1].u64, buf[2].ptr as *mut u8) };
|
||||
unsafe { crate::RustBuffer::from_raw_parts(data, len, capacity) }
|
||||
}
|
||||
|
||||
fn put(buf: &mut [FfiBufferElement], value: Self) {
|
||||
buf[0].u64 = value.capacity;
|
||||
buf[1].u64 = value.len;
|
||||
buf[2].ptr = value.data as *const std::ffi::c_void;
|
||||
}
|
||||
}
|
||||
|
||||
impl FfiSerialize for RustCallStatus {
|
||||
const SIZE: usize = 4;
|
||||
|
||||
fn get(buf: &[FfiBufferElement]) -> Self {
|
||||
// Safety: the foreign bindings are responsible for sending us the correct data.
|
||||
let code = unsafe { buf[0].i8 };
|
||||
Self {
|
||||
code: RustCallStatusCode::try_from(code).unwrap_or(RustCallStatusCode::UnexpectedError),
|
||||
error_buf: MaybeUninit::new(RustBuffer::get(&buf[1..])),
|
||||
}
|
||||
}
|
||||
|
||||
fn put(buf: &mut [FfiBufferElement], value: Self) {
|
||||
buf[0].i8 = value.code as i8;
|
||||
// Safety: This is okay even if the error buf is not initialized. It just means we'll be
|
||||
// copying the garbage data.
|
||||
unsafe { RustBuffer::put(&mut buf[1..], value.error_buf.assume_init()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::{Handle, RustBuffer, RustCallStatus, RustCallStatusCode};
|
||||
|
||||
#[test]
|
||||
fn test_ffi_buffer_size() {
|
||||
assert_eq!(ffi_buffer_size!(u8), 1);
|
||||
assert_eq!(ffi_buffer_size!(i8), 1);
|
||||
assert_eq!(ffi_buffer_size!(u16), 1);
|
||||
assert_eq!(ffi_buffer_size!(i16), 1);
|
||||
assert_eq!(ffi_buffer_size!(u32), 1);
|
||||
assert_eq!(ffi_buffer_size!(i32), 1);
|
||||
assert_eq!(ffi_buffer_size!(u64), 1);
|
||||
assert_eq!(ffi_buffer_size!(i64), 1);
|
||||
assert_eq!(ffi_buffer_size!(f32), 1);
|
||||
assert_eq!(ffi_buffer_size!(f64), 1);
|
||||
assert_eq!(ffi_buffer_size!(bool), 1);
|
||||
assert_eq!(ffi_buffer_size!(*const std::ffi::c_void), 1);
|
||||
assert_eq!(ffi_buffer_size!(RustBuffer), 3);
|
||||
assert_eq!(ffi_buffer_size!(RustCallStatus), 4);
|
||||
assert_eq!(ffi_buffer_size!(Handle), 1);
|
||||
assert_eq!(ffi_buffer_size!(()), 0);
|
||||
|
||||
assert_eq!(ffi_buffer_size!(u8, f32, bool, Handle, (), RustBuffer), 7);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ffi_serialize() {
|
||||
let mut some_data = vec![1, 2, 3];
|
||||
let void_ptr = some_data.as_mut_ptr() as *const std::ffi::c_void;
|
||||
let rust_buffer = unsafe { RustBuffer::from_raw_parts(some_data.as_mut_ptr(), 2, 3) };
|
||||
let orig_rust_buffer_data = (
|
||||
rust_buffer.data_pointer(),
|
||||
rust_buffer.len(),
|
||||
rust_buffer.capacity(),
|
||||
);
|
||||
let handle = Handle::from_raw(101).unwrap();
|
||||
let rust_call_status = RustCallStatus::new();
|
||||
let rust_call_status_error_buf = unsafe { rust_call_status.error_buf.assume_init_ref() };
|
||||
let orig_rust_call_status_buffer_data = (
|
||||
rust_call_status_error_buf.data_pointer(),
|
||||
rust_call_status_error_buf.len(),
|
||||
rust_call_status_error_buf.capacity(),
|
||||
);
|
||||
let mut buf = [FfiBufferElement::default(); 21];
|
||||
let mut buf_writer = buf.as_mut_slice();
|
||||
<u8 as FfiSerialize>::write(&mut buf_writer, 0);
|
||||
<i8 as FfiSerialize>::write(&mut buf_writer, 1);
|
||||
<u16 as FfiSerialize>::write(&mut buf_writer, 2);
|
||||
<i16 as FfiSerialize>::write(&mut buf_writer, 3);
|
||||
<u32 as FfiSerialize>::write(&mut buf_writer, 4);
|
||||
<i32 as FfiSerialize>::write(&mut buf_writer, 5);
|
||||
<u64 as FfiSerialize>::write(&mut buf_writer, 6);
|
||||
<i64 as FfiSerialize>::write(&mut buf_writer, 7);
|
||||
<f32 as FfiSerialize>::write(&mut buf_writer, 0.1);
|
||||
<f64 as FfiSerialize>::write(&mut buf_writer, 0.2);
|
||||
<bool as FfiSerialize>::write(&mut buf_writer, true);
|
||||
<*const std::ffi::c_void as FfiSerialize>::write(&mut buf_writer, void_ptr);
|
||||
<RustBuffer as FfiSerialize>::write(&mut buf_writer, rust_buffer);
|
||||
<RustCallStatus as FfiSerialize>::write(&mut buf_writer, rust_call_status);
|
||||
<Handle as FfiSerialize>::write(&mut buf_writer, handle);
|
||||
#[allow(unknown_lints)]
|
||||
#[allow(clippy::needless_borrows_for_generic_args)]
|
||||
<() as FfiSerialize>::write(&mut buf_writer, ());
|
||||
|
||||
let mut buf_reader = buf.as_slice();
|
||||
assert_eq!(<u8 as FfiSerialize>::read(&mut buf_reader), 0);
|
||||
assert_eq!(<i8 as FfiSerialize>::read(&mut buf_reader), 1);
|
||||
assert_eq!(<u16 as FfiSerialize>::read(&mut buf_reader), 2);
|
||||
assert_eq!(<i16 as FfiSerialize>::read(&mut buf_reader), 3);
|
||||
assert_eq!(<u32 as FfiSerialize>::read(&mut buf_reader), 4);
|
||||
assert_eq!(<i32 as FfiSerialize>::read(&mut buf_reader), 5);
|
||||
assert_eq!(<u64 as FfiSerialize>::read(&mut buf_reader), 6);
|
||||
assert_eq!(<i64 as FfiSerialize>::read(&mut buf_reader), 7);
|
||||
assert_eq!(<f32 as FfiSerialize>::read(&mut buf_reader), 0.1);
|
||||
assert_eq!(<f64 as FfiSerialize>::read(&mut buf_reader), 0.2);
|
||||
assert!(<bool as FfiSerialize>::read(&mut buf_reader));
|
||||
assert_eq!(
|
||||
<*const std::ffi::c_void as FfiSerialize>::read(&mut buf_reader),
|
||||
void_ptr
|
||||
);
|
||||
let rust_buffer2 = <RustBuffer as FfiSerialize>::read(&mut buf_reader);
|
||||
assert_eq!(
|
||||
(
|
||||
rust_buffer2.data_pointer(),
|
||||
rust_buffer2.len(),
|
||||
rust_buffer2.capacity()
|
||||
),
|
||||
orig_rust_buffer_data,
|
||||
);
|
||||
|
||||
let rust_call_status2 = <RustCallStatus as FfiSerialize>::read(&mut buf_reader);
|
||||
assert_eq!(rust_call_status2.code, RustCallStatusCode::Success);
|
||||
|
||||
let rust_call_status2_error_buf = unsafe { rust_call_status2.error_buf.assume_init() };
|
||||
assert_eq!(
|
||||
(
|
||||
rust_call_status2_error_buf.data_pointer(),
|
||||
rust_call_status2_error_buf.len(),
|
||||
rust_call_status2_error_buf.capacity(),
|
||||
),
|
||||
orig_rust_call_status_buffer_data
|
||||
);
|
||||
assert_eq!(<Handle as FfiSerialize>::read(&mut buf_reader), handle);
|
||||
// Ensure that `read` with a unit struct doesn't panic. No need to assert anything, since
|
||||
// the return type is ().
|
||||
<() as FfiSerialize>::read(&mut buf_reader);
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
//! This module defines a Rust Future that wraps an async foreign function call.
|
||||
//!
|
||||
//! The general idea is to create a [oneshot::Channel], hand the sender to the foreign side, and
|
||||
//! The general idea is to create a oneshot channel, hand the sender to the foreign side, and
|
||||
//! await the receiver side on the Rust side.
|
||||
//!
|
||||
//! The foreign side should:
|
||||
|
@ -17,7 +17,7 @@
|
|||
//! * Wait for the [ForeignFutureHandle::free] function to be called to free the task object.
|
||||
//! If this is called before the task completes, then the task will be cancelled.
|
||||
|
||||
use crate::{LiftReturn, RustCallStatus, UnexpectedUniFFICallbackError};
|
||||
use crate::{oneshot, LiftReturn, RustCallStatus};
|
||||
|
||||
/// Handle for a foreign future
|
||||
pub type ForeignFutureHandle = u64;
|
||||
|
@ -69,15 +69,8 @@ where
|
|||
// The important thing is that the ForeignFuture will be dropped when this Future is.
|
||||
let _foreign_future =
|
||||
call_scaffolding_function(foreign_future_complete::<T, UT>, sender.into_raw() as u64);
|
||||
match receiver.await {
|
||||
Ok(result) => T::lift_foreign_return(result.return_value, result.call_status),
|
||||
Err(e) => {
|
||||
// This shouldn't happen in practice, but we can do our best to recover
|
||||
T::handle_callback_unexpected_error(UnexpectedUniFFICallbackError::new(format!(
|
||||
"Error awaiting foreign future: {e}"
|
||||
)))
|
||||
}
|
||||
}
|
||||
let result = receiver.await;
|
||||
T::lift_foreign_return(result.return_value, result.call_status)
|
||||
}
|
||||
|
||||
pub extern "C" fn foreign_future_complete<T: LiftReturn<UT>, UT>(
|
||||
|
@ -85,10 +78,7 @@ pub extern "C" fn foreign_future_complete<T: LiftReturn<UT>, UT>(
|
|||
result: ForeignFutureResult<T::ReturnType>,
|
||||
) {
|
||||
let channel = unsafe { oneshot::Sender::from_raw(oneshot_handle as *mut ()) };
|
||||
// Ignore errors in send.
|
||||
//
|
||||
// Error means the receiver was already dropped which will happen when the future is cancelled.
|
||||
let _ = channel.send(result);
|
||||
channel.send(result);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
pub mod callbackinterface;
|
||||
pub mod ffidefault;
|
||||
#[cfg(feature = "scaffolding-ffi-buffer-fns")]
|
||||
pub mod ffiserialize;
|
||||
pub mod foreignbytes;
|
||||
pub mod foreigncallbacks;
|
||||
pub mod foreignfuture;
|
||||
|
@ -16,6 +18,8 @@ pub mod rustfuture;
|
|||
|
||||
pub use callbackinterface::*;
|
||||
pub use ffidefault::FfiDefault;
|
||||
#[cfg(feature = "scaffolding-ffi-buffer-fns")]
|
||||
pub use ffiserialize::FfiSerialize;
|
||||
pub use foreignbytes::*;
|
||||
pub use foreigncallbacks::*;
|
||||
pub use foreignfuture::*;
|
||||
|
|
|
@ -53,12 +53,12 @@ use crate::ffi::{rust_call, ForeignBytes, RustCallStatus};
|
|||
pub struct RustBuffer {
|
||||
/// The allocated capacity of the underlying `Vec<u8>`.
|
||||
/// In Rust this is a `usize`, but we use an `u64` to keep the foreign binding code simple.
|
||||
capacity: u64,
|
||||
pub(crate) capacity: u64,
|
||||
/// The occupied length of the underlying `Vec<u8>`.
|
||||
/// In Rust this is a `usize`, but we use an `u64` to keep the foreign binding code simple.
|
||||
len: u64,
|
||||
pub(crate) len: u64,
|
||||
/// The pointer to the allocated buffer of the `Vec<u8>`.
|
||||
data: *mut u8,
|
||||
pub(crate) data: *mut u8,
|
||||
}
|
||||
|
||||
// Mark `RustBuffer` as safe to send between threads, despite the `u8` pointer. The only mutable
|
||||
|
@ -107,6 +107,12 @@ impl RustBuffer {
|
|||
.expect("buffer length negative or overflowed")
|
||||
}
|
||||
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.capacity
|
||||
.try_into()
|
||||
.expect("buffer length negative or overflowed")
|
||||
}
|
||||
|
||||
/// Get a pointer to the data
|
||||
pub fn data_pointer(&self) -> *const u8 {
|
||||
self.data
|
||||
|
|
|
@ -106,6 +106,20 @@ pub enum RustCallStatusCode {
|
|||
Cancelled = 3,
|
||||
}
|
||||
|
||||
impl TryFrom<i8> for RustCallStatusCode {
|
||||
type Error = i8;
|
||||
|
||||
fn try_from(value: i8) -> Result<Self, i8> {
|
||||
match value {
|
||||
0 => Ok(Self::Success),
|
||||
1 => Ok(Self::Error),
|
||||
2 => Ok(Self::UnexpectedError),
|
||||
3 => Ok(Self::Cancelled),
|
||||
n => Err(n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle a scaffolding calls
|
||||
///
|
||||
/// `callback` is responsible for making the actual Rust call and returning a special result type:
|
||||
|
|
|
@ -42,7 +42,10 @@ pub mod ffi;
|
|||
mod ffi_converter_impls;
|
||||
mod ffi_converter_traits;
|
||||
pub mod metadata;
|
||||
mod oneshot;
|
||||
|
||||
#[cfg(feature = "scaffolding-ffi-buffer-fns")]
|
||||
pub use ffi::ffiserialize::FfiBufferElement;
|
||||
pub use ffi::*;
|
||||
pub use ffi_converter_traits::{
|
||||
ConvertError, FfiConverter, FfiConverterArc, HandleAlloc, Lift, LiftRef, LiftReturn, Lower,
|
||||
|
@ -58,7 +61,6 @@ pub mod deps {
|
|||
pub use async_compat;
|
||||
pub use bytes;
|
||||
pub use log;
|
||||
pub use oneshot;
|
||||
pub use static_assertions;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/* 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/. */
|
||||
|
||||
//! Implements a simple oneshot channel.
|
||||
//!
|
||||
//! We used to use the `oneshot` crate for this, but the dependency was hard to manage
|
||||
//! (https://github.com/mozilla/uniffi-rs/issues/1736)
|
||||
//!
|
||||
//! This implementation is less efficient, but the difference is probably negligible for most
|
||||
//! use-cases involving UniFFI.
|
||||
|
||||
use std::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
sync::{Arc, Mutex},
|
||||
task::{Context, Poll, Waker},
|
||||
};
|
||||
|
||||
pub struct Sender<T>(Arc<Mutex<OneshotInner<T>>>);
|
||||
pub struct Receiver<T>(Arc<Mutex<OneshotInner<T>>>);
|
||||
|
||||
struct OneshotInner<T> {
|
||||
value: Option<T>,
|
||||
waker: Option<Waker>,
|
||||
}
|
||||
|
||||
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
|
||||
let arc = Arc::new(Mutex::new(OneshotInner {
|
||||
value: None,
|
||||
waker: None,
|
||||
}));
|
||||
(Sender(arc.clone()), Receiver(arc))
|
||||
}
|
||||
|
||||
impl<T> Sender<T> {
|
||||
/// Send a value to the receiver
|
||||
pub fn send(self, value: T) {
|
||||
let mut inner = self.0.lock().unwrap();
|
||||
inner.value = Some(value);
|
||||
if let Some(waker) = inner.waker.take() {
|
||||
waker.wake();
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a Sender into a raw pointer
|
||||
///
|
||||
/// from_raw must be called with this pointer or else the sender will leak
|
||||
pub fn into_raw(self) -> *const () {
|
||||
Arc::into_raw(self.0) as *const ()
|
||||
}
|
||||
|
||||
/// Convert a raw pointer back to a Sender
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `raw_ptr` must have come from into_raw(). Once a pointer is passed into `from_raw` it must
|
||||
/// not be used again.
|
||||
pub unsafe fn from_raw(raw_ptr: *const ()) -> Self {
|
||||
Self(Arc::from_raw(raw_ptr as *const Mutex<OneshotInner<T>>))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Future for Receiver<T> {
|
||||
type Output = T;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let mut inner = self.0.lock().unwrap();
|
||||
match inner.value.take() {
|
||||
Some(v) => Poll::Ready(v),
|
||||
None => {
|
||||
inner.waker = Some(cx.waker().clone());
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"a292239ca3c72852768fdf0e7bc2dd6386af7bf1ab0ef56dff01e1c9e781b2ca","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","src/custom.rs":"36cd6c2eeb8efdc34e59dff634a22e79471ab17f49ceb0f131da5f144313f7e4","src/default.rs":"77466ac54da69094bcdccc5927d0980b1e9dd0095647ca825830673c48847a53","src/enum_.rs":"afe0a6534d8e7f68047e3f1afad9369d5d5650f4c7555e8d4173f24126c715ba","src/error.rs":"30168378da9a23e6530ffe68647bf6618d07a0aaa236d5009137a922798a0e88","src/export.rs":"42c5e784c1dccc796c8b6ea29c2dc1811e48a531488a3ed0e2a59330778a7e41","src/export/attributes.rs":"c848f8c309c4cf7a168f038834752dc4816b5c853768d7c331ea4cd5ce0841b7","src/export/callback_interface.rs":"794b0665dc7eb02ea854c61c8bb2781e0b4ac1de646d95a8fd7791f770f2e6e3","src/export/item.rs":"4e86875692c2d2993fde12e78dbde2cbffa5675ede143577d5620126401efe05","src/export/scaffolding.rs":"b25167d2213b6d6c5ba653622f26791e8c3e74a5ecce6512ec27009fc8bf68e4","src/export/trait_interface.rs":"f07f9908ee28661de4586d89b693f3d93dae5e5cba8a089eff25f20bbf6b373b","src/export/utrait.rs":"b55533d3eef8262944d3c0d9a3a9cba0615d2d5af8608f0919abc7699989e2a8","src/fnsig.rs":"5e434a1cc87166c5245424bb14e896eb766bf680d4d50d4b8536852f91487d7c","src/lib.rs":"a28bbfd2d1dc835306ff6072f75761bb6b3a158477bba966057776c527fe6d70","src/object.rs":"5419ed64c8120aef811a77c2205f58a7a537bdf34ae04f9c92dd3aaa176eed39","src/record.rs":"29072542cc2f3e027bd7c59b45ba913458f8213d1b2b33bc70d140baa98fcdc8","src/setup_scaffolding.rs":"173fdc916967d54bd6532def16d12e5bb85467813a46a031d3338b77625756bb","src/test.rs":"1673f282bb35d6b0740ad0e5f11826c2852d7a0db29604c2258f457415b537e8","src/util.rs":"a2c3693343e78dffb2a7f7b39eeb9b7f298b66688f1766a7c08113cf9431ef4c"},"package":"18331d35003f46f0d04047fbe4227291815b83a937a8c32bc057f990962182c4"}
|
||||
{"files":{"Cargo.toml":"32636b759af83af70f08c4573c101f0467eb8469c318d08dcfbc4578fe456660","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","src/custom.rs":"36cd6c2eeb8efdc34e59dff634a22e79471ab17f49ceb0f131da5f144313f7e4","src/default.rs":"77466ac54da69094bcdccc5927d0980b1e9dd0095647ca825830673c48847a53","src/enum_.rs":"afe0a6534d8e7f68047e3f1afad9369d5d5650f4c7555e8d4173f24126c715ba","src/error.rs":"30168378da9a23e6530ffe68647bf6618d07a0aaa236d5009137a922798a0e88","src/export.rs":"42c5e784c1dccc796c8b6ea29c2dc1811e48a531488a3ed0e2a59330778a7e41","src/export/attributes.rs":"c848f8c309c4cf7a168f038834752dc4816b5c853768d7c331ea4cd5ce0841b7","src/export/callback_interface.rs":"794b0665dc7eb02ea854c61c8bb2781e0b4ac1de646d95a8fd7791f770f2e6e3","src/export/item.rs":"4e86875692c2d2993fde12e78dbde2cbffa5675ede143577d5620126401efe05","src/export/scaffolding.rs":"03abb762391f67b43bec89dae8f57b54b014133193a8337436f4129de51fb987","src/export/trait_interface.rs":"f07f9908ee28661de4586d89b693f3d93dae5e5cba8a089eff25f20bbf6b373b","src/export/utrait.rs":"b55533d3eef8262944d3c0d9a3a9cba0615d2d5af8608f0919abc7699989e2a8","src/fnsig.rs":"5e434a1cc87166c5245424bb14e896eb766bf680d4d50d4b8536852f91487d7c","src/lib.rs":"a28bbfd2d1dc835306ff6072f75761bb6b3a158477bba966057776c527fe6d70","src/object.rs":"5419ed64c8120aef811a77c2205f58a7a537bdf34ae04f9c92dd3aaa176eed39","src/record.rs":"29072542cc2f3e027bd7c59b45ba913458f8213d1b2b33bc70d140baa98fcdc8","src/setup_scaffolding.rs":"173fdc916967d54bd6532def16d12e5bb85467813a46a031d3338b77625756bb","src/test.rs":"1673f282bb35d6b0740ad0e5f11826c2852d7a0db29604c2258f457415b537e8","src/util.rs":"d1b7b80d0bcc43b7794cd2dbdd89194f84b098343f9e0a3f1843e91c95e1ded3"},"package":"b6f08d5592c669b80a8af5066027098bebec4b4af17a9b8b299bac5f518ab89e"}
|
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2021"
|
||||
name = "uniffi_macros"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
|
||||
description = "a multi-language bindings generator for rust (convenience macros)"
|
||||
homepage = "https://mozilla.github.io/uniffi-rs"
|
||||
|
@ -61,13 +61,14 @@ features = [
|
|||
version = "0.5.9"
|
||||
|
||||
[dependencies.uniffi_build]
|
||||
version = "=0.27.1"
|
||||
version = "=0.27.3"
|
||||
optional = true
|
||||
|
||||
[dependencies.uniffi_meta]
|
||||
version = "=0.27.1"
|
||||
version = "=0.27.3"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
nightly = []
|
||||
scaffolding-ffi-buffer-fns = []
|
||||
trybuild = ["dep:uniffi_build"]
|
||||
|
|
|
@ -244,6 +244,12 @@ pub(super) fn gen_ffi_function(
|
|||
let return_impl = &sig.lower_return_impl();
|
||||
|
||||
Ok(if !sig.is_async {
|
||||
let scaffolding_fn_ffi_buffer_version = ffi_buffer_scaffolding_fn(
|
||||
&ffi_ident,
|
||||
"e! { <#return_ty as ::uniffi::LowerReturn<crate::UniFfiTag>>::ReturnType },
|
||||
¶m_types,
|
||||
true,
|
||||
);
|
||||
quote! {
|
||||
#[doc(hidden)]
|
||||
#[no_mangle]
|
||||
|
@ -267,12 +273,16 @@ pub(super) fn gen_ffi_function(
|
|||
)
|
||||
})
|
||||
}
|
||||
|
||||
#scaffolding_fn_ffi_buffer_version
|
||||
}
|
||||
} else {
|
||||
let mut future_expr = rust_fn_call;
|
||||
if matches!(ar, Some(AsyncRuntime::Tokio(_))) {
|
||||
future_expr = quote! { ::uniffi::deps::async_compat::Compat::new(#future_expr) }
|
||||
}
|
||||
let scaffolding_fn_ffi_buffer_version =
|
||||
ffi_buffer_scaffolding_fn(&ffi_ident, "e! { ::uniffi::Handle}, ¶m_types, false);
|
||||
|
||||
quote! {
|
||||
#[doc(hidden)]
|
||||
|
@ -300,6 +310,71 @@ pub(super) fn gen_ffi_function(
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
#scaffolding_fn_ffi_buffer_version
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "scaffolding-ffi-buffer-fns")]
|
||||
fn ffi_buffer_scaffolding_fn(
|
||||
fn_ident: &Ident,
|
||||
return_type: &TokenStream,
|
||||
param_types: &[TokenStream],
|
||||
has_rust_call_status: bool,
|
||||
) -> TokenStream {
|
||||
let fn_name = fn_ident.to_string();
|
||||
let ffi_buffer_fn_name = uniffi_meta::ffi_buffer_symbol_name(&fn_name);
|
||||
let ident = Ident::new(&ffi_buffer_fn_name, proc_macro2::Span::call_site());
|
||||
let type_list: Vec<_> = param_types.iter().map(|ty| quote! { #ty }).collect();
|
||||
if has_rust_call_status {
|
||||
quote! {
|
||||
#[doc(hidden)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn #ident(
|
||||
arg_ptr: *mut ::uniffi::FfiBufferElement,
|
||||
return_ptr: *mut ::uniffi::FfiBufferElement,
|
||||
) {
|
||||
let mut arg_buf = unsafe { ::std::slice::from_raw_parts(arg_ptr, ::uniffi::ffi_buffer_size!(#(#type_list),*)) };
|
||||
let mut return_buf = unsafe { ::std::slice::from_raw_parts_mut(return_ptr, ::uniffi::ffi_buffer_size!(#return_type, ::uniffi::RustCallStatus)) };
|
||||
let mut out_status = ::uniffi::RustCallStatus::default();
|
||||
|
||||
let return_value = #fn_ident(
|
||||
#(
|
||||
<#type_list as ::uniffi::FfiSerialize>::read(&mut arg_buf),
|
||||
)*
|
||||
&mut out_status,
|
||||
);
|
||||
<#return_type as ::uniffi::FfiSerialize>::write(&mut return_buf, return_value);
|
||||
<::uniffi::RustCallStatus as ::uniffi::FfiSerialize>::write(&mut return_buf, out_status);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#[doc(hidden)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn #ident(
|
||||
arg_ptr: *mut ::uniffi::FfiBufferElement,
|
||||
return_ptr: *mut ::uniffi::FfiBufferElement,
|
||||
) {
|
||||
let mut arg_buf = unsafe { ::std::slice::from_raw_parts(arg_ptr, ::uniffi::ffi_buffer_size!(#(#type_list),*)) };
|
||||
let mut return_buf = unsafe { ::std::slice::from_raw_parts_mut(return_ptr, ::uniffi::ffi_buffer_size!(#return_type)) };
|
||||
|
||||
let return_value = #fn_ident(#(
|
||||
<#type_list as ::uniffi::FfiSerialize>::read(&mut arg_buf),
|
||||
)*);
|
||||
<#return_type as ::uniffi::FfiSerialize>::put(&mut return_buf, return_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "scaffolding-ffi-buffer-fns"))]
|
||||
fn ffi_buffer_scaffolding_fn(
|
||||
_fn_ident: &Ident,
|
||||
_return_type: &TokenStream,
|
||||
_param_types: &[TokenStream],
|
||||
_add_rust_call_status: bool,
|
||||
) -> TokenStream {
|
||||
quote! {}
|
||||
}
|
||||
|
|
|
@ -110,7 +110,6 @@ pub fn create_metadata_items(
|
|||
let const_ident =
|
||||
format_ident!("UNIFFI_META_CONST_{crate_name_upper}_{kind_upper}_{name_upper}");
|
||||
let static_ident = format_ident!("UNIFFI_META_{crate_name_upper}_{kind_upper}_{name_upper}");
|
||||
|
||||
let checksum_fn = checksum_fn_name.map(|name| {
|
||||
let ident = Ident::new(&name, Span::call_site());
|
||||
quote! {
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"5620cf9840477b158641547703ba353e3ad8427ec7b20b9dd5e5f5fe4df7d6d2","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","src/ffi_names.rs":"ca38b700a0a103c9faaf456ed91b67adf46d4e750aee9e9cd01ad97fb1840494","src/group.rs":"d0a43f3c528aba9403649715981ad3a8849d7a370f4ef9e2d618b88f60a3102f","src/lib.rs":"3f00d5214e2785e4b3045bc48899f6f6b1dce32ab3da6be3ebce716ee9d24c5f","src/metadata.rs":"3f236b337a1fd5082ea9cc4fee6800193a903ee88b81f1c3202843402f122a14","src/reader.rs":"579e2b87d8dd9d703b8811294abfb992621c0a46765800e4db2fad2906db2208","src/types.rs":"c2c5188da8cdf5af7f8496d4660bcfaa971b81ed73b64486c05b47256048544f"},"package":"f7224422c4cfd181c7ca9fca2154abca4d21db962f926f270f996edd38b0c4b8"}
|
||||
{"files":{"Cargo.toml":"3d53a00cb590863149f9e68505581ccbfc635ac1bb2b59d692f5d679cd1732bc","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","src/ffi_names.rs":"240e04f257fd199e268ff16d5979f521cb9d18e21d494981718fa2b96956324d","src/group.rs":"d0a43f3c528aba9403649715981ad3a8849d7a370f4ef9e2d618b88f60a3102f","src/lib.rs":"3f00d5214e2785e4b3045bc48899f6f6b1dce32ab3da6be3ebce716ee9d24c5f","src/metadata.rs":"3f236b337a1fd5082ea9cc4fee6800193a903ee88b81f1c3202843402f122a14","src/reader.rs":"579e2b87d8dd9d703b8811294abfb992621c0a46765800e4db2fad2906db2208","src/types.rs":"c2c5188da8cdf5af7f8496d4660bcfaa971b81ed73b64486c05b47256048544f"},"package":"583bab49f2bdf5681f9732f8b67a7e555ad920dbb5427be21450217bf1818189"}
|
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2021"
|
||||
name = "uniffi_meta"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
description = "uniffi_meta"
|
||||
homepage = "https://mozilla.github.io/uniffi-rs"
|
||||
readme = "README.md"
|
||||
|
@ -33,4 +33,4 @@ version = "1.3"
|
|||
version = "0.3"
|
||||
|
||||
[dependencies.uniffi_checksum_derive]
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
|
|
|
@ -73,3 +73,12 @@ pub fn method_checksum_symbol_name(namespace: &str, object_name: &str, name: &st
|
|||
let name = name.to_ascii_lowercase();
|
||||
format!("uniffi_{namespace}_checksum_method_{object_name}_{name}")
|
||||
}
|
||||
|
||||
/// Get the symbol name for a FFI-buffer version of a function
|
||||
pub fn ffi_buffer_symbol_name(fn_name: &str) -> String {
|
||||
match fn_name.strip_prefix("uniffi_") {
|
||||
Some(rest) => format!("uniffi_ffibuffer_{rest}"),
|
||||
// this should never happen, but if it does let's try our best to prefix things properl.
|
||||
None => format!("uniffi_ffibuffer_{fn_name}"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"f29ebbc363e01ee31c5a351aa6c19bc99343b4d293d5ea7954bca3f49e77ad54","README.md":"ec6aba24af9a011ef6647422aa22efabdee519cdee3da1a9f9033b07b7cbdb0d","src/lib.rs":"e19f60aed5a137401203b9054ead27894b98490bab3e2f680a23549c8ee8a13a"},"package":"f8ce878d0bdfc288b58797044eaaedf748526c56eef3575380bb4d4b19d69eee"}
|
||||
{"files":{"Cargo.toml":"02452729580c718585b4cc1cbaa2d09aa97ebec62c4d0bd3fdb50d6063cfe036","README.md":"ec6aba24af9a011ef6647422aa22efabdee519cdee3da1a9f9033b07b7cbdb0d","src/lib.rs":"e19f60aed5a137401203b9054ead27894b98490bab3e2f680a23549c8ee8a13a"},"package":"13963044ca9bde9b709d2eee68bc11dafc7acea144ae0fdc0cf29ed4add44481"}
|
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2021"
|
||||
name = "uniffi_testing"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
|
||||
description = "a multi-language bindings generator for rust (testing helpers)"
|
||||
homepage = "https://mozilla.github.io/uniffi-rs"
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"e4553df91528daadbc52244f436c3ae17d9c6a4629d232643a20ed63c1311625","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","src/attributes.rs":"f1cdee01db837920dbd109d60b39dd4b0ece56f83797fe4ace1e0caf97c02483","src/collectors.rs":"00c9cd8e8f7be6949996f069b449f120f0b0694ff2f1ca92b79201721c18c594","src/converters/callables.rs":"1ad26c2782629e98272edc75c38343f58194ebf9626ae451ba84546a60d45a48","src/converters/enum_.rs":"aa0ca7a7a50521a45e296c6f53be5f1981a41872443946f72c2ca8baebe4d69b","src/converters/interface.rs":"6042d4abd5e236ed6158c5f6d4d9b81bb01fbbcb8b42bf8a5b385b978c68f6f8","src/converters/mod.rs":"c34a30e3b7a2e3c092a7074f4bab6f6c34364177c096af59a7dda13e44ffdc3c","src/finder.rs":"3586ffd3772151eabbc3d6062725933c88978e1b5feb64312bbf42cd43af30fa","src/lib.rs":"56c50ce61ba5e7266fe7fc9fa9d0022cdbfbe9801730753bd4ee66fed040221c","src/literal.rs":"4f28ad49a17246b4dc30a677cfff65b345bfac0924856e19f58e7574a74c2c40","src/resolver.rs":"c4ff362055dc4ed489e94a063ec0fd3becb8787ad35ce65cdec437a1aae518a0"},"package":"8c43c9ed40a8d20a5c3eae2d23031092db6b96dc8e571beb449ba9757484cea0"}
|
||||
{"files":{"Cargo.toml":"eda87b82f785000e7ac4d07d24285dc5a961d8109bd90dfd134f8545a86f3b56","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","src/attributes.rs":"f1cdee01db837920dbd109d60b39dd4b0ece56f83797fe4ace1e0caf97c02483","src/collectors.rs":"00c9cd8e8f7be6949996f069b449f120f0b0694ff2f1ca92b79201721c18c594","src/converters/callables.rs":"1ad26c2782629e98272edc75c38343f58194ebf9626ae451ba84546a60d45a48","src/converters/enum_.rs":"aa0ca7a7a50521a45e296c6f53be5f1981a41872443946f72c2ca8baebe4d69b","src/converters/interface.rs":"6042d4abd5e236ed6158c5f6d4d9b81bb01fbbcb8b42bf8a5b385b978c68f6f8","src/converters/mod.rs":"c34a30e3b7a2e3c092a7074f4bab6f6c34364177c096af59a7dda13e44ffdc3c","src/finder.rs":"3586ffd3772151eabbc3d6062725933c88978e1b5feb64312bbf42cd43af30fa","src/lib.rs":"56c50ce61ba5e7266fe7fc9fa9d0022cdbfbe9801730753bd4ee66fed040221c","src/literal.rs":"4f28ad49a17246b4dc30a677cfff65b345bfac0924856e19f58e7574a74c2c40","src/resolver.rs":"c4ff362055dc4ed489e94a063ec0fd3becb8787ad35ce65cdec437a1aae518a0"},"package":"b92f984bb0d9a06778f256aec963e1e9a80714014f7a90fb0e01008821fe5a97"}
|
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2021"
|
||||
name = "uniffi_udl"
|
||||
version = "0.27.1"
|
||||
version = "0.27.3"
|
||||
description = "udl parsing for the uniffi project"
|
||||
homepage = "https://mozilla.github.io/uniffi-rs"
|
||||
documentation = "https://mozilla.github.io/uniffi-rs"
|
||||
|
@ -29,12 +29,14 @@ version = "1"
|
|||
|
||||
[dependencies.textwrap]
|
||||
version = "0.16"
|
||||
features = ["smawk"]
|
||||
default-features = false
|
||||
|
||||
[dependencies.uniffi_meta]
|
||||
version = "=0.27.1"
|
||||
version = "=0.27.3"
|
||||
|
||||
[dependencies.uniffi_testing]
|
||||
version = "=0.27.1"
|
||||
version = "=0.27.3"
|
||||
|
||||
[dependencies.weedle2]
|
||||
version = "5.0.0"
|
||||
|
|
Загрузка…
Ссылка в новой задаче