Vendor things

This commit is contained in:
John Doty 2024-03-08 11:03:01 -08:00
parent 5deceec006
commit 977e3c17e5
19434 changed files with 10682014 additions and 0 deletions

View file

@ -0,0 +1 @@
{"files":{"CHANGELOG.md":"286ba5ef14c3199cfc510c4693aa8dbf660543d4b016e2a00fcd190cca7390ae","Cargo.toml":"4569ac021d9983cef708a827f5d6437fea5be84df2dbb51622b1d9a51019a638","README.md":"38470ee1aaa43e6436c23f62bf05788dd23c7dad92669b69a7dc8d4868d4bdef","src/block.rs":"16aa845511ed2e2dbd259da62e6beb9bbb51cf544b6c10d48341931b132ee063","src/concrete_block.rs":"9ad053ebad2e5747d3397b74a95381f3bda2866918d1bff4abd714180ea7f431","src/debug.rs":"c25742c777ffde5c0d7bb4bb1c78e935a16c2775951ea031655cb995302742db","src/global.rs":"460b807f90421899814fe61a35e909fb494b8d90c2f7349dbbf4b76fb5906604","src/lib.rs":"c54c67952867c2c62581d11573712976c46f988793120653b5692872c893baa3","src/rc_block.rs":"58504e8660547d379c93f03c5368b48b09fa37ea91d26f9fcf529b9186f309f4"},"package":"8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42"}

164
third-party/vendor/block2/CHANGELOG.md vendored Normal file
View file

@ -0,0 +1,164 @@
# Changelog
Notable changes to this crate will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## Unreleased - YYYY-MM-DD
## 0.2.0-alpha.6 - 2022-08-28
### Changed
* **BREAKING**: Updated `objc2-encode` to `v2.0.0-pre.2`.
* Updated `ffi` module to `block-sys v0.1.0-beta.1`.
### Fixed
* **BREAKING**: Cleaned up `BlockArguments` trait, it is now sealed and a
subtrait of `EncodeArguments`.
* **BREAKING**: Cleaned up `IntoConcreteBlock` trait, it is now sealed and the
associated output type has been renamed to `Output`.
## 0.2.0-alpha.5 - 2022-07-19
### Added
* Implemented `Debug` for `Block`, `ConcreteBlock`, `RcBlock` and
`GlobalBlock`.
### Changed
* **BREAKING**: Updated `objc2-encode` to `v2.0.0-pre.1`.
* Updated `ffi` module to `block-sys v0.1.0-beta.0`.
## 0.2.0-alpha.4 - 2022-06-13
### Changed
* **BREAKING**: Updated `objc2-encode` to `v2.0.0-pre.0`.
* **BREAKING**: Updated `ffi` module to `block-sys v0.0.4`.
### Removed
* **BREAKING**: Removed `DerefMut` implementation for `ConcreteBlock`.
## 0.2.0-alpha.3 - 2022-01-03
### Changed
* Changed `global_block!` macro to take an optional semicolon at the end.
* Improved documentation.
* **BREAKING**: Updated `ffi` module to `block-sys v0.0.3`.
## 0.2.0-alpha.2 - 2021-12-22
### Added
* `GlobalBlock` and corresponding `global_block!` macro, allowing statically
creating blocks that don't reference their environment.
### Changed
* **BREAKING**: Updated `ffi` module to `block-sys v0.0.2`
## 0.2.0-alpha.1 - 2021-11-22
### Added
* Proper GNUStep support using `block-sys`. See that crate for usage.
* Export `block-sys` as `ffi` module.
### Removed
* Dependency on `objc_test_utils`.
### Fixed
* `ConcreteBlock` no longer allocates block descriptors on the heap.
* Better unwind safety in `ConcreteBlock::copy`.
## 0.2.0-alpha.0 - 2021-10-28
### Added
* **BREAKING**: Blocks now require that arguments and return type implement
`objc2_encode::Encode`. This is a safety measure to prevent creating blocks
with invalid arguments.
* Blocks now implements `objc2_encode::RefEncode` (and as such can be used in
Objective-C message sends).
* Update to 2018 edition.
### Changed
* **BREAKING**: Forked the project, so it is now available under the name
`block2`.
### Fixed
* Soundness issues with using empty enums over FFI.
## [0.1.6] (`block` crate) - 2016-05-08
### Added
* Support for linking to `libBlocksRuntime`.
## [0.1.5] (`block` crate) - 2016-04-04
### Changed
* Minor code changes
## [0.1.4] (`block` crate) - 2015-11-12
### Removed
* `libc` dependency.
## [0.1.3] (`block` crate) - 2015-11-07
### Changed
* Updated `libc` dependency.
## [0.1.2] (`block` crate) - 2015-10-10
### Fixed
* `improper_ctypes` warning.
## [0.1.1] (`block` crate) - 2015-09-03
### Fixed
* Missing `Sized` bounds on traits.
## [0.1.0] (`block` crate) - 2015-05-18
### Added
* `Clone` implementation for `RcBlock`.
* Improved documentation.
### Changed
* **BREAKING**: Rename `IdBlock` to `RcBlock`.
* **BREAKING**: Make `Block::call` take self immutably and make it `unsafe`.
* **BREAKING**: Make `BlockArguments::call_block` `unsafe`.
### Removed
* **BREAKING**: `DerefMut` on `RcBlock`.
* `objc` dependency.
* `Foundation` dependency in tests.
## [0.0.2] (`block` crate) - 2015-05-02
### Changed
* Use `objc_id`.
## [0.0.1] (`block` crate) - 2015-04-17
Initial version.
[0.1.6]: https://github.com/madsmtm/objc2/compare/block-0.1.5...block-0.1.6
[0.1.5]: https://github.com/madsmtm/objc2/compare/block-0.1.4...block-0.1.5
[0.1.4]: https://github.com/madsmtm/objc2/compare/block-0.1.3...block-0.1.4
[0.1.3]: https://github.com/madsmtm/objc2/compare/block-0.1.2...block-0.1.3
[0.1.2]: https://github.com/madsmtm/objc2/compare/block-0.1.1...block-0.1.2
[0.1.1]: https://github.com/madsmtm/objc2/compare/block-0.1.0...block-0.1.1
[0.1.0]: https://github.com/madsmtm/objc2/compare/block-0.0.2...block-0.1.0
[0.0.2]: https://github.com/madsmtm/objc2/compare/block-0.0.1...block-0.0.2
[0.0.1]: https://github.com/madsmtm/objc2/releases/tag/block-0.0.1

103
third-party/vendor/block2/Cargo.toml vendored Normal file
View file

@ -0,0 +1,103 @@
# 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"
name = "block2"
version = "0.2.0-alpha.6"
authors = [
"Steven Sheldon",
"Mads Marquart <mads@marquart.dk>",
]
description = "Apple's C language extension of blocks"
documentation = "https://docs.rs/block2/"
readme = "README.md"
keywords = [
"objective-c",
"macos",
"ios",
"blocks",
]
categories = [
"api-bindings",
"development-tools::ffi",
"os::macos-apis",
]
license = "MIT"
repository = "https://github.com/madsmtm/objc2"
resolver = "2"
[package.metadata.docs.rs]
default-target = "x86_64-apple-darwin"
targets = [
"x86_64-apple-darwin",
"aarch64-apple-darwin",
"aarch64-apple-ios",
"x86_64-apple-ios",
"x86_64-unknown-linux-gnu",
"i686-unknown-linux-gnu",
"x86_64-pc-windows-msvc",
]
[dependencies.block-sys]
version = "=0.1.0-beta.1"
default-features = false
[dependencies.objc2-encode]
version = "=2.0.0-pre.2"
default-features = false
[features]
alloc = [
"objc2-encode/alloc",
"block-sys/alloc",
]
apple = [
"block-sys/apple",
"objc2-encode/apple",
]
compiler-rt = [
"block-sys/compiler-rt",
"objc2-encode/apple",
]
default = [
"std",
"apple",
]
gnustep-1-7 = [
"block-sys/gnustep-1-7",
"objc2-encode/gnustep-1-7",
]
gnustep-1-8 = [
"gnustep-1-7",
"block-sys/gnustep-1-8",
"objc2-encode/gnustep-1-8",
]
gnustep-1-9 = [
"gnustep-1-8",
"block-sys/gnustep-1-9",
"objc2-encode/gnustep-1-9",
]
gnustep-2-0 = [
"gnustep-1-9",
"block-sys/gnustep-2-0",
"objc2-encode/gnustep-2-0",
]
gnustep-2-1 = [
"gnustep-2-0",
"block-sys/gnustep-2-1",
"objc2-encode/gnustep-2-1",
]
std = [
"alloc",
"objc2-encode/std",
"block-sys/std",
]

16
third-party/vendor/block2/README.md vendored Normal file
View file

@ -0,0 +1,16 @@
# `block2`
[![Latest version](https://badgen.net/crates/v/block2)](https://crates.io/crates/block2)
[![License](https://badgen.net/badge/license/MIT/blue)](../LICENSE.txt)
[![Documentation](https://docs.rs/block2/badge.svg)](https://docs.rs/block2/)
[![CI](https://github.com/madsmtm/objc2/actions/workflows/ci.yml/badge.svg)](https://github.com/madsmtm/objc2/actions/workflows/ci.yml)
Apple's C language extension of blocks in Rust.
This crate provides functionality for interracting with C blocks, effectively
the C-equivalent of Rust's closures.
See [the docs](https://docs.rs/block2/) for a more thorough overview.
This crate is part of the [`objc2` project](https://github.com/madsmtm/objc2),
see that for related crates.

118
third-party/vendor/block2/src/block.rs vendored Normal file
View file

@ -0,0 +1,118 @@
use core::marker::PhantomData;
use core::mem;
use objc2_encode::{Encode, EncodeArguments, Encoding, RefEncode};
use crate::ffi;
/// Types that may be used as the arguments of an Objective-C block.
///
/// This is implemented for tuples of up to 12 arguments, where each argument
/// implements [`Encode`].
///
///
/// # Safety
///
/// This is a sealed trait, and should not need to be implemented. Open an
/// issue if you know a use-case where this restrition should be lifted!
pub unsafe trait BlockArguments: EncodeArguments + Sized {
/// Calls the given method the block and arguments.
#[doc(hidden)]
unsafe fn __call_block<R: Encode>(
invoke: unsafe extern "C" fn(),
block: *mut Block<Self, R>,
args: Self,
) -> R;
}
macro_rules! block_args_impl {
($($a:ident: $t:ident),*) => (
unsafe impl<$($t: Encode),*> BlockArguments for ($($t,)*) {
#[inline]
unsafe fn __call_block<R: Encode>(invoke: unsafe extern "C" fn(), block: *mut Block<Self, R>, ($($a,)*): Self) -> R {
// Very similar to `MessageArguments::__invoke`
let invoke: unsafe extern "C" fn(*mut Block<Self, R> $(, $t)*) -> R = unsafe {
mem::transmute(invoke)
};
unsafe { invoke(block $(, $a)*) }
}
}
);
}
block_args_impl!();
block_args_impl!(a: A);
block_args_impl!(a: A, b: B);
block_args_impl!(a: A, b: B, c: C);
block_args_impl!(a: A, b: B, c: C, d: D);
block_args_impl!(a: A, b: B, c: C, d: D, e: E);
block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
block_args_impl!(
a: A,
b: B,
c: C,
d: D,
e: E,
f: F,
g: G,
h: H,
i: I,
j: J,
k: K
);
block_args_impl!(
a: A,
b: B,
c: C,
d: D,
e: E,
f: F,
g: G,
h: H,
i: I,
j: J,
k: K,
l: L
);
/// An Objective-C block that takes arguments of `A` when called and
/// returns a value of `R`.
#[repr(C)]
pub struct Block<A, R> {
_inner: [u8; 0],
// We effectively store `Block_layout` + a bit more, but `Block` has to
// remain an empty type otherwise the compiler thinks we only have
// provenance over `Block_layout`.
_layout: PhantomData<ffi::Block_layout>,
// To get correct variance on args and return types
_p: PhantomData<fn(A) -> R>,
}
unsafe impl<A: BlockArguments, R: Encode> RefEncode for Block<A, R> {
const ENCODING_REF: Encoding = Encoding::Block;
}
impl<A: BlockArguments, R: Encode> Block<A, R> {
/// Call self with the given arguments.
///
/// # Safety
///
/// This invokes foreign code that the caller must verify doesn't violate
/// any of Rust's safety rules.
///
/// For example, if this block is shared with multiple references, the
/// caller must ensure that calling it will not cause a data race.
pub unsafe fn call(&self, args: A) -> R {
let ptr: *const Self = self;
let layout = unsafe { ptr.cast::<ffi::Block_layout>().as_ref().unwrap_unchecked() };
// TODO: Is `invoke` actually ever null?
let invoke = layout.invoke.unwrap();
unsafe { A::__call_block(invoke, ptr as *mut Self, args) }
}
}

View file

@ -0,0 +1,254 @@
use core::ffi::c_void;
use core::marker::PhantomData;
use core::mem::{self, ManuallyDrop};
use core::ops::Deref;
use core::ptr;
use std::os::raw::c_ulong;
use objc2_encode::{Encode, Encoding, RefEncode};
use crate::{ffi, Block, BlockArguments, RcBlock};
mod private {
pub trait Sealed<A> {}
}
/// Types that may be converted into a [`ConcreteBlock`].
///
/// This is implemented for [`Fn`] closures of up to 12 arguments, where each
/// argument and the return type implements [`Encode`].
///
///
/// # Safety
///
/// This is a sealed trait, and should not need to be implemented. Open an
/// issue if you know a use-case where this restrition should be lifted!
pub unsafe trait IntoConcreteBlock<A: BlockArguments>: private::Sealed<A> + Sized {
/// The return type of the resulting `ConcreteBlock`.
type Output: Encode;
#[doc(hidden)]
fn __into_concrete_block(self) -> ConcreteBlock<A, Self::Output, Self>;
}
macro_rules! concrete_block_impl {
($f:ident) => (
concrete_block_impl!($f,);
);
($f:ident, $($a:ident : $t:ident),*) => (
impl<$($t: Encode,)* R: Encode, X> private::Sealed<($($t,)*)> for X
where
X: Fn($($t,)*) -> R,
{}
unsafe impl<$($t: Encode,)* R: Encode, X> IntoConcreteBlock<($($t,)*)> for X
where
X: Fn($($t,)*) -> R,
{
type Output = R;
fn __into_concrete_block(self) -> ConcreteBlock<($($t,)*), R, X> {
extern "C" fn $f<$($t,)* R, X>(
block: &ConcreteBlock<($($t,)*), R, X>,
$($a: $t,)*
) -> R
where
X: Fn($($t,)*) -> R,
{
(block.closure)($($a),*)
}
let f: extern "C" fn(&ConcreteBlock<($($t,)*), R, X>, $($a: $t,)*) -> R = $f;
let f: unsafe extern "C" fn() = unsafe { mem::transmute(f) };
unsafe { ConcreteBlock::with_invoke(f, self) }
}
}
);
}
concrete_block_impl!(concrete_block_invoke_args0);
concrete_block_impl!(concrete_block_invoke_args1, a: A);
concrete_block_impl!(concrete_block_invoke_args2, a: A, b: B);
concrete_block_impl!(concrete_block_invoke_args3, a: A, b: B, c: C);
concrete_block_impl!(concrete_block_invoke_args4, a: A, b: B, c: C, d: D);
concrete_block_impl!(concrete_block_invoke_args5, a: A, b: B, c: C, d: D, e: E);
concrete_block_impl!(
concrete_block_invoke_args6,
a: A,
b: B,
c: C,
d: D,
e: E,
f: F
);
concrete_block_impl!(
concrete_block_invoke_args7,
a: A,
b: B,
c: C,
d: D,
e: E,
f: F,
g: G
);
concrete_block_impl!(
concrete_block_invoke_args8,
a: A,
b: B,
c: C,
d: D,
e: E,
f: F,
g: G,
h: H
);
concrete_block_impl!(
concrete_block_invoke_args9,
a: A,
b: B,
c: C,
d: D,
e: E,
f: F,
g: G,
h: H,
i: I
);
concrete_block_impl!(
concrete_block_invoke_args10,
a: A,
b: B,
c: C,
d: D,
e: E,
f: F,
g: G,
h: H,
i: I,
j: J
);
concrete_block_impl!(
concrete_block_invoke_args11,
a: A,
b: B,
c: C,
d: D,
e: E,
f: F,
g: G,
h: H,
i: I,
j: J,
k: K
);
concrete_block_impl!(
concrete_block_invoke_args12,
a: A,
b: B,
c: C,
d: D,
e: E,
f: F,
g: G,
h: H,
i: I,
j: J,
k: K,
l: L
);
/// An Objective-C block whose size is known at compile time and may be
/// constructed on the stack.
#[repr(C)]
pub struct ConcreteBlock<A, R, F> {
p: PhantomData<Block<A, R>>,
pub(crate) layout: ffi::Block_layout,
pub(crate) closure: F,
}
unsafe impl<A: BlockArguments, R: Encode, F> RefEncode for ConcreteBlock<A, R, F> {
const ENCODING_REF: Encoding = Encoding::Block;
}
impl<A, R, F> ConcreteBlock<A, R, F>
where
A: BlockArguments,
R: Encode,
F: IntoConcreteBlock<A, Output = R>,
{
/// Constructs a `ConcreteBlock` with the given closure.
/// When the block is called, it will return the value that results from
/// calling the closure.
pub fn new(closure: F) -> Self {
closure.__into_concrete_block()
}
}
impl<A, R, F> ConcreteBlock<A, R, F> {
// TODO: Use new ABI with BLOCK_HAS_SIGNATURE
const FLAGS: ffi::block_flags = ffi::BLOCK_HAS_COPY_DISPOSE;
const DESCRIPTOR: ffi::Block_descriptor = ffi::Block_descriptor {
header: ffi::Block_descriptor_header {
reserved: 0,
size: mem::size_of::<Self>() as c_ulong,
},
copy: Some(block_context_copy::<Self>),
dispose: Some(block_context_dispose::<Self>),
};
/// Constructs a `ConcreteBlock` with the given invoke function and closure.
/// Unsafe because the caller must ensure the invoke function takes the
/// correct arguments.
unsafe fn with_invoke(invoke: unsafe extern "C" fn(), closure: F) -> Self {
let layout = ffi::Block_layout {
isa: unsafe { &ffi::_NSConcreteStackBlock },
flags: Self::FLAGS,
reserved: 0,
invoke: Some(invoke),
descriptor: &Self::DESCRIPTOR as *const ffi::Block_descriptor as *mut c_void,
};
Self {
p: PhantomData,
layout,
closure,
}
}
}
impl<A, R, F: 'static> ConcreteBlock<A, R, F> {
/// Copy self onto the heap as an `RcBlock`.
pub fn copy(self) -> RcBlock<A, R> {
// Our copy helper will run so the block will be moved to the heap
// and we can forget the original block because the heap block will
// drop in our dispose helper. TODO: Verify this.
let mut block = ManuallyDrop::new(self);
let ptr: *mut Self = &mut *block;
unsafe { RcBlock::copy(ptr.cast()) }
}
}
impl<A, R, F: Clone> Clone for ConcreteBlock<A, R, F> {
fn clone(&self) -> Self {
unsafe { Self::with_invoke(self.layout.invoke.unwrap(), self.closure.clone()) }
}
}
impl<A, R, F> Deref for ConcreteBlock<A, R, F> {
type Target = Block<A, R>;
fn deref(&self) -> &Self::Target {
let ptr: *const Self = self;
let ptr: *const Block<A, R> = ptr.cast();
// TODO: SAFETY
unsafe { ptr.as_ref().unwrap_unchecked() }
}
}
unsafe extern "C" fn block_context_dispose<B>(block: *mut c_void) {
unsafe { ptr::drop_in_place(block.cast::<B>()) };
}
unsafe extern "C" fn block_context_copy<B>(_dst: *mut c_void, _src: *mut c_void) {
// The runtime memmoves the src block into the dst block, nothing to do
}

242
third-party/vendor/block2/src/debug.rs vendored Normal file
View file

@ -0,0 +1,242 @@
use alloc::format;
use core::ffi::c_void;
use core::fmt::{Debug, DebugStruct, Error, Formatter};
use core::ptr;
use std::ffi::CStr;
use crate::{ffi, Block, ConcreteBlock, GlobalBlock, RcBlock};
#[derive(Clone, Copy, PartialEq, Eq)]
struct Isa(*const ffi::Class);
impl Isa {
fn is_global(self) -> bool {
ptr::eq(unsafe { &ffi::_NSConcreteGlobalBlock }, self.0)
}
fn is_stack(self) -> bool {
ptr::eq(unsafe { &ffi::_NSConcreteStackBlock }, self.0)
}
fn is_malloc(self) -> bool {
ptr::eq(unsafe { &ffi::_NSConcreteMallocBlock }, self.0)
}
}
impl Debug for Isa {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
if self.is_global() {
f.write_str("_NSConcreteGlobalBlock")
} else if self.is_stack() {
f.write_str("_NSConcreteStackBlock")
} else if self.is_malloc() {
f.write_str("_NSConcreteMallocBlock")
} else {
write!(f, "{:?}", self.0)
}
}
}
fn debug_block_layout(layout: &ffi::Block_layout, f: &mut DebugStruct<'_, '_>) {
f.field("isa", &Isa(layout.isa));
f.field("flags", &BlockFlags(layout.flags));
f.field("reserved", &layout.reserved);
f.field("invoke", &layout.invoke);
f.field(
"descriptor",
&BlockDescriptor {
has_copy_dispose: layout.flags & ffi::BLOCK_HAS_COPY_DISPOSE != 0,
has_signature: layout.flags & ffi::BLOCK_HAS_SIGNATURE != 0,
descriptor: layout.descriptor,
},
);
}
impl<A, R> Debug for Block<A, R> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
let mut f = f.debug_struct("Block");
let ptr: *const Self = self;
let layout = unsafe { ptr.cast::<ffi::Block_layout>().as_ref().unwrap() };
debug_block_layout(layout, &mut f);
f.finish_non_exhaustive()
}
}
impl<A, R> Debug for RcBlock<A, R> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
let mut f = f.debug_struct("RcBlock");
let layout = unsafe { self.ptr.cast::<ffi::Block_layout>().as_ref().unwrap() };
debug_block_layout(layout, &mut f);
f.finish_non_exhaustive()
}
}
impl<A, R, F: Debug> Debug for ConcreteBlock<A, R, F> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
let mut f = f.debug_struct("ConcreteBlock");
debug_block_layout(&self.layout, &mut f);
f.field("closure", &self.closure);
f.finish()
}
}
impl<A, R> Debug for GlobalBlock<A, R> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
let mut f = f.debug_struct("GlobalBlock");
debug_block_layout(&self.layout, &mut f);
f.finish_non_exhaustive()
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
struct BlockFlags(ffi::block_flags);
impl Debug for BlockFlags {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
let mut f = f.debug_struct("BlockFlags");
f.field("value", &format!("{:032b}", self.0));
macro_rules! test_flags {
{$(
$(#[$m:meta])?
$name:ident: $flag:ident
);* $(;)?} => ($(
$(#[$m])?
f.field(stringify!($name), &(self.0 & ffi::$flag != 0));
)*)
}
test_flags! {
#[cfg(feature = "apple")]
deallocating: BLOCK_DEALLOCATING;
#[cfg(feature = "apple")]
inline_layout_string: BLOCK_INLINE_LAYOUT_STRING;
#[cfg(feature = "apple")]
small_descriptor: BLOCK_SMALL_DESCRIPTOR;
#[cfg(feature = "apple")]
is_noescape: BLOCK_IS_NOESCAPE;
#[cfg(feature = "apple")]
needs_free: BLOCK_NEEDS_FREE;
has_copy_dispose: BLOCK_HAS_COPY_DISPOSE;
has_ctor: BLOCK_HAS_CTOR;
#[cfg(feature = "apple")]
is_gc: BLOCK_IS_GC;
is_global: BLOCK_IS_GLOBAL;
use_stret: BLOCK_USE_STRET;
has_signature: BLOCK_HAS_SIGNATURE;
#[cfg(feature = "apple")]
has_extended_layout: BLOCK_HAS_EXTENDED_LAYOUT;
}
f.field(
"over_referenced",
&(self.0 & ffi::BLOCK_REFCOUNT_MASK == ffi::BLOCK_REFCOUNT_MASK),
);
f.field(
"reference_count",
&((self.0 & ffi::BLOCK_REFCOUNT_MASK) >> 1),
);
f.finish_non_exhaustive()
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
struct BlockDescriptor {
has_copy_dispose: bool,
has_signature: bool,
descriptor: *const c_void,
}
impl Debug for BlockDescriptor {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
if self.descriptor.is_null() {
return f.write_str("(null)");
}
let mut f = f.debug_struct("BlockDescriptor");
let header = unsafe {
self.descriptor
.cast::<ffi::Block_descriptor_header>()
.as_ref()
.unwrap()
};
f.field("reserved", &header.reserved);
f.field("size", &header.size);
match (self.has_copy_dispose, self.has_signature) {
(false, false) => {}
(true, false) => {
let descriptor = unsafe {
self.descriptor
.cast::<ffi::Block_descriptor>()
.as_ref()
.unwrap()
};
f.field("copy", &descriptor.copy);
f.field("dispose", &descriptor.dispose);
}
(false, true) => {
let descriptor = unsafe {
self.descriptor
.cast::<ffi::Block_descriptor_basic>()
.as_ref()
.unwrap()
};
f.field(
"encoding",
&if descriptor.encoding.is_null() {
None
} else {
Some(unsafe { CStr::from_ptr(descriptor.encoding) })
},
);
}
(true, true) => {
let descriptor = unsafe {
self.descriptor
.cast::<ffi::Block_descriptor_with_signature>()
.as_ref()
.unwrap()
};
f.field("copy", &descriptor.copy);
f.field("dispose", &descriptor.dispose);
f.field(
"encoding",
&if descriptor.encoding.is_null() {
None
} else {
Some(unsafe { CStr::from_ptr(descriptor.encoding) })
},
);
}
}
f.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_isa() {
let isa = Isa(unsafe { &ffi::_NSConcreteGlobalBlock });
assert!(isa.is_global());
assert!(!isa.is_stack());
assert!(!isa.is_malloc());
let isa = Isa(unsafe { &ffi::_NSConcreteStackBlock });
assert!(!isa.is_global());
assert!(isa.is_stack());
assert!(!isa.is_malloc());
let isa = Isa(unsafe { &ffi::_NSConcreteMallocBlock });
assert!(!isa.is_global());
assert!(!isa.is_stack());
assert!(isa.is_malloc());
let isa = Isa(ptr::null());
assert!(!isa.is_global());
assert!(!isa.is_stack());
assert!(!isa.is_malloc());
}
}

274
third-party/vendor/block2/src/global.rs vendored Normal file
View file

@ -0,0 +1,274 @@
use core::ffi::c_void;
use core::marker::PhantomData;
use core::mem;
use core::ops::Deref;
use core::ptr;
use std::os::raw::c_ulong;
use objc2_encode::Encode;
use super::{ffi, Block};
use crate::BlockArguments;
// TODO: Should this be a static to help the compiler deduplicating them?
const GLOBAL_DESCRIPTOR: ffi::Block_descriptor_header = ffi::Block_descriptor_header {
reserved: 0,
size: mem::size_of::<ffi::Block_layout>() as c_ulong,
};
/// An Objective-C block that does not capture its environment.
///
/// This is effectively just a glorified function pointer, and can created and
/// stored in static memory using the [`global_block!`] macro.
///
/// If [`ConcreteBlock`] is the [`Fn`]-block equivalent, this is likewise the
/// [`fn`]-block equivalent.
///
/// [`ConcreteBlock`]: crate::ConcreteBlock
/// [`global_block!`]: crate::global_block
#[repr(C)]
pub struct GlobalBlock<A, R = ()> {
pub(crate) layout: ffi::Block_layout,
p: PhantomData<(A, R)>,
}
unsafe impl<A, R> Sync for GlobalBlock<A, R>
where
A: BlockArguments,
R: Encode,
{
}
unsafe impl<A, R> Send for GlobalBlock<A, R>
where
A: BlockArguments,
R: Encode,
{
}
// Note: We can't put correct bounds on A and R because we have a const fn!
//
// Fortunately, we don't need them, since they're present on `Sync`, so
// constructing the static in `global_block!` with an invalid `GlobalBlock`
// triggers an error.
impl<A, R> GlobalBlock<A, R> {
// TODO: Use new ABI with BLOCK_HAS_SIGNATURE
const FLAGS: ffi::block_flags = ffi::BLOCK_IS_GLOBAL | ffi::BLOCK_USE_STRET;
#[doc(hidden)]
pub const __DEFAULT_LAYOUT: ffi::Block_layout = ffi::Block_layout {
// Populated in `global_block!`
isa: ptr::null_mut(),
flags: Self::FLAGS,
reserved: 0,
// Populated in `global_block!`
invoke: None,
descriptor: &GLOBAL_DESCRIPTOR as *const ffi::Block_descriptor_header as *mut c_void,
};
/// Use the [`global_block`] macro instead.
#[doc(hidden)]
pub const unsafe fn from_layout(layout: ffi::Block_layout) -> Self {
Self {
layout,
p: PhantomData,
}
}
}
impl<A, R> Deref for GlobalBlock<A, R>
where
A: BlockArguments,
R: Encode,
{
type Target = Block<A, R>;
fn deref(&self) -> &Self::Target {
let ptr: *const Self = self;
let ptr: *const Block<A, R> = ptr.cast();
// TODO: SAFETY
unsafe { ptr.as_ref().unwrap_unchecked() }
}
}
/// Construct a static [`GlobalBlock`].
///
/// The syntax is similar to a static closure (except that all types have to
/// be specified). Note that the block cannot capture its environment, and
/// its argument types and return type must be [`Encode`].
///
/// # Examples
///
/// ```
/// use block2::global_block;
/// global_block! {
/// static MY_BLOCK = || -> i32 {
/// 42
/// };
/// }
/// assert_eq!(unsafe { MY_BLOCK.call(()) }, 42);
/// ```
///
/// ```
/// use block2::global_block;
/// global_block! {
/// static ADDER_BLOCK = |x: i32, y: i32| -> i32 {
/// x + y
/// };
/// }
/// assert_eq!(unsafe { ADDER_BLOCK.call((5, 7)) }, 12);
/// ```
///
/// ```
/// use block2::global_block;
/// global_block! {
/// pub static MUTATING_BLOCK = |x: &mut i32| {
/// *x = *x + 42;
/// };
/// }
/// let mut x = 5;
/// unsafe { MUTATING_BLOCK.call((&mut x,)) };
/// assert_eq!(x, 47);
/// ```
///
/// The following does not compile because [`Box`] is not [`Encode`]:
///
/// ```compile_fail
/// use block2::global_block;
/// global_block! {
/// pub static BLOCK = |b: Box<i32>| {};
/// }
/// ```
///
/// There is also no way to get a block function that's generic over its
/// arguments. One could imagine the following syntax would work, but it can't
/// due to implementation limitations:
///
/// ```compile_fail
/// use block2::global_block;
/// global_block! {
/// pub static BLOCK<T: Encode> = |b: T| {};
/// }
/// ```
///
/// [`Box`]: std::boxed::Box
#[macro_export]
macro_rules! global_block {
// `||` is parsed as one token
(
$(#[$m:meta])*
$vis:vis static $name:ident = || $(-> $r:ty)? $body:block $(;)?
) => {
$crate::global_block!(
$(#[$m])*
$vis static $name = |,| $(-> $r)? $body
);
};
(
$(#[$m:meta])*
$vis:vis static $name:ident = |$($a:ident: $t:ty),* $(,)?| $(-> $r:ty)? $body:block $(;)?
) => {
$(#[$m])*
#[allow(unused_unsafe)]
$vis static $name: $crate::GlobalBlock<($($t,)*) $(, $r)?> = unsafe {
let mut layout = $crate::GlobalBlock::<($($t,)*) $(, $r)?>::__DEFAULT_LAYOUT;
layout.isa = &$crate::ffi::_NSConcreteGlobalBlock;
layout.invoke = ::core::option::Option::Some({
unsafe extern "C" fn inner(_: *mut $crate::ffi::Block_layout, $($a: $t),*) $(-> $r)? {
$body
}
let inner: unsafe extern "C" fn(*mut $crate::ffi::Block_layout, $($a: $t),*) $(-> $r)? = inner;
// TODO: SAFETY
::core::mem::transmute(inner)
});
$crate::GlobalBlock::from_layout(layout)
};
};
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::format;
global_block! {
/// Test comments and visibility
pub(super) static NOOP_BLOCK = || {};
}
global_block! {
/// Multiple arguments + trailing comma
#[allow(unused)]
static BLOCK = |x: i32, y: i32, z: i32, w: i32,| -> i32 {
x + y + z + w
};
}
#[test]
fn test_noop_block() {
unsafe { NOOP_BLOCK.call(()) };
}
#[test]
fn test_defined_in_function() {
global_block!(static MY_BLOCK = || -> i32 {
42
});
assert_eq!(unsafe { MY_BLOCK.call(()) }, 42);
}
#[cfg(feature = "apple")]
const DEBUG_BLOCKFLAGS: &str = r#"BlockFlags {
value: "00110000000000000000000000000000",
deallocating: false,
inline_layout_string: false,
small_descriptor: false,
is_noescape: false,
needs_free: false,
has_copy_dispose: false,
has_ctor: false,
is_gc: false,
is_global: true,
use_stret: true,
has_signature: false,
has_extended_layout: false,
over_referenced: false,
reference_count: 0,
..
}"#;
#[cfg(not(feature = "apple"))]
const DEBUG_BLOCKFLAGS: &str = r#"BlockFlags {
value: "00110000000000000000000000000000",
has_copy_dispose: false,
has_ctor: false,
is_global: true,
use_stret: true,
has_signature: false,
over_referenced: false,
reference_count: 0,
..
}"#;
#[test]
fn test_debug() {
let invoke = NOOP_BLOCK.layout.invoke.unwrap();
let size = mem::size_of::<ffi::Block_layout>();
let expected = format!(
"GlobalBlock {{
isa: _NSConcreteGlobalBlock,
flags: {DEBUG_BLOCKFLAGS},
reserved: 0,
invoke: Some(
{invoke:#?},
),
descriptor: BlockDescriptor {{
reserved: 0,
size: {size},
}},
..
}}"
);
assert_eq!(format!("{:#?}", NOOP_BLOCK), expected);
}
}

109
third-party/vendor/block2/src/lib.rs vendored Normal file
View file

@ -0,0 +1,109 @@
//! # Apple's C language extension of blocks
//!
//! C Blocks are effectively the C-equivalent of Rust's closures, in that they
//! have the ability to capture their environments.
//!
//! This crate provides capabilities to create and invoke these blocks, in an
//! ergonomic "Rust-centric" fashion.
//!
//! For more information on the specifics of the block implementation, see the
//! [C language specification][lang] and the [ABI specification][ABI].
//!
//! (Note that while this library can be used separately from Objective-C,
//! they're most commonly used together).
//!
//! ## Invoking blocks
//!
//! The [`Block`] struct is used for invoking blocks from Objective-C. For
//! example, consider this Objective-C function that takes a block as a
//! parameter, executes the block with some arguments, and returns the result:
//!
//! ```objc
//! #include <stdint.h>
//! #include <Block.h>
//! int32_t run_block(int32_t (^block)(int32_t, int32_t)) {
//! return block(5, 8);
//! }
//! ```
//!
//! We could write the equivalent function in Rust like this:
//!
//! ```
//! use block2::Block;
//! unsafe fn run_block(block: &Block<(i32, i32), i32>) -> i32 {
//! block.call((5, 8))
//! }
//! ```
//!
//! Note the extra parentheses in the `call` method, since the arguments must
//! be passed as a tuple.
//!
//! ## Creating blocks
//!
//! Creating a block to pass to Objective-C can be done with the
//! [`ConcreteBlock`] struct. For example, to create a block that adds two
//! integers, we could write:
//!
//! ```
//! use block2::ConcreteBlock;
//! let block = ConcreteBlock::new(|a: i32, b: i32| a + b);
//! let block = block.copy();
//! assert_eq!(unsafe { block.call((5, 8)) }, 13);
//! ```
//!
//! It is important to copy your block to the heap (with the [`copy`] method)
//! before passing it to Objective-C; this is because our [`ConcreteBlock`] is
//! only meant to be copied once, and we can enforce this in Rust, but if
//! Objective-C code were to copy it twice we could have a double free.
//!
//! [`copy`]: ConcreteBlock::copy
//!
//! As an optimization if your block doesn't capture any variables, you can
//! use the [`global_block!`] macro to create a static block:
//!
//! ```
//! use block2::global_block;
//! global_block! {
//! static MY_BLOCK = || -> f32 {
//! 10.0
//! };
//! }
//! assert_eq!(unsafe { MY_BLOCK.call(()) }, 10.0);
//! ```
//!
//! [lang]: https://clang.llvm.org/docs/BlockLanguageSpec.html
//! [ABI]: http://clang.llvm.org/docs/Block-ABI-Apple.html
#![no_std]
#![warn(elided_lifetimes_in_paths)]
#![warn(missing_docs)]
#![deny(non_ascii_idents)]
#![warn(unreachable_pub)]
#![deny(unsafe_op_in_unsafe_fn)]
#![warn(clippy::cargo)]
#![warn(clippy::ptr_as_ptr)]
// Update in Cargo.toml as well.
#![doc(html_root_url = "https://docs.rs/block2/0.2.0-alpha.6")]
extern crate alloc;
extern crate std;
#[cfg(not(feature = "std"))]
compile_error!("The `std` feature currently must be enabled.");
#[cfg(doctest)]
#[doc = include_str!("../README.md")]
extern "C" {}
pub use block_sys as ffi;
mod block;
mod concrete_block;
mod debug;
mod global;
mod rc_block;
pub use block::{Block, BlockArguments};
pub use concrete_block::{ConcreteBlock, IntoConcreteBlock};
pub use global::GlobalBlock;
pub use rc_block::RcBlock;

View file

@ -0,0 +1,59 @@
use core::ops::Deref;
use crate::{ffi, Block};
/// A reference-counted Objective-C block.
pub struct RcBlock<A, R> {
pub(crate) ptr: *mut Block<A, R>,
}
impl<A, R> RcBlock<A, R> {
/// Construct an `RcBlock` for the given block without copying it.
/// The caller must ensure the block has a +1 reference count.
///
/// # Safety
///
/// The given pointer must point to a valid `Block` and must have a +1
/// reference count or it will be overreleased when the `RcBlock` is
/// dropped.
pub unsafe fn new(ptr: *mut Block<A, R>) -> Self {
RcBlock { ptr }
}
/// Constructs an `RcBlock` by copying the given block.
///
/// # Safety
///
/// The given pointer must point to a valid `Block`.
pub unsafe fn copy(ptr: *mut Block<A, R>) -> Self {
// SAFETY: The caller ensures the pointer is valid.
let ptr: *mut Block<A, R> = unsafe { ffi::_Block_copy(ptr.cast()) }.cast();
// SAFETY: We just copied the block, so the reference count is +1
//
// TODO: Does _Block_copy always returns a valid pointer?
unsafe { Self::new(ptr) }
}
}
impl<A, R> Clone for RcBlock<A, R> {
fn clone(&self) -> RcBlock<A, R> {
// SAFETY: The pointer is valid, since the only way to get an RcBlock
// in the first place is through unsafe functions.
unsafe { RcBlock::copy(self.ptr) }
}
}
impl<A, R> Deref for RcBlock<A, R> {
type Target = Block<A, R>;
fn deref(&self) -> &Block<A, R> {
// SAFETY: The pointer is ensured valid by creator functions.
unsafe { self.ptr.as_ref().unwrap_unchecked() }
}
}
impl<A, R> Drop for RcBlock<A, R> {
fn drop(&mut self) {
unsafe { ffi::_Block_release(self.ptr.cast()) };
}
}