Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
1
third-party/vendor/objc2-encode/.cargo-checksum.json
vendored
Normal file
1
third-party/vendor/objc2-encode/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"CHANGELOG.md":"e8391ac7ae2a5c701636e9369c5909340f930ace6d9227eadd94ba88b37f0fdd","Cargo.lock":"90988905fc575a458a243b36ae2277d487c6c99703c41b199b5ca5a0ae746939","Cargo.toml":"3007205192dbd967f1f2020c6501699530cac1f63721ae87ce7be1ec2264288e","README.md":"89a1402faf702ad0a4a69f8019e885bc90eb39c58a81c87d3023ab89832202d6","examples/core_graphics.rs":"9c219e6907a14230eee24cdf8690ebd5e17e66ff147362795ec4c08f3a1a265e","examples/ns_string.rs":"e62539091a1973df2a764a05c2532065f1613c76bb2a6bb4c531e7c87cfc28d7","examples/ns_uinteger.rs":"7a5b1c49fa6770997f1ca58619cccfb4a5c239639c5ed6fbcdcc262e13344cfa","examples/opaque_type.rs":"9dbcfde73c050c5bffc9016d7e3a4b98b7a9389067fd49aaecea243e6f0ced07","src/__bool.rs":"c75312eb4862788e6b8baf39dc022e36cfe1d5f681e5a34a4bdd6675ea399478","src/encode.rs":"c2b69ef25119a558a07bb642858ea00fb873ad1507e7373afb07683ee3c3d7d8","src/encoding.rs":"ff19fe45fe3c4fb33627267cb176dfb54454dcdd719e0fc4402cefd0f3e13ed2","src/helper.rs":"2bb406940c58c354f1c9f1850e0941c483562013ffa58a9637a0bee3986ee505","src/lib.rs":"7ee68b5822bdff295c177ce5dd12692f4b84b237d31437d991f214386d0a7f1d","src/parse.rs":"1243d0102865c66cc721499222baf008d23081b8df6c7553b313e3281c7cfea8","src/static_str.rs":"21294faaaf3a08c11e7806d025aa3884220b6f6e7611a6d351b1a4023a5a7d29"},"package":"abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512"}
|
||||
195
third-party/vendor/objc2-encode/CHANGELOG.md
vendored
Normal file
195
third-party/vendor/objc2-encode/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
# 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
|
||||
|
||||
## 2.0.0-pre.2 - 2022-08-28
|
||||
|
||||
### Added
|
||||
* Added `EncodeConvert` trait to help with correctly handling `BOOL`/`bool`.
|
||||
|
||||
### Changed
|
||||
* **BREAKING**: Remove the lifetime specifier from `Encoding`, since the non
|
||||
-`'static` version was essentially useless.
|
||||
|
||||
### Fixed
|
||||
* Fixed the encoding output and comparison of structs behind pointers.
|
||||
|
||||
### Removed
|
||||
* **BREAKING**: `bool` (and `AtomicBool`) no longer implements `Encode`, since
|
||||
that was difficult to use correctly. See the `EncodeConvert` trait, or use
|
||||
`objc2::runtime::Bool` instead.
|
||||
|
||||
|
||||
## 2.0.0-pre.1 - 2022-07-19
|
||||
|
||||
### Added
|
||||
* Added `Encoding::Atomic`.
|
||||
* Implement `Encode` and `RefEncode` for `std::sync::atomic` types.
|
||||
|
||||
### Changed
|
||||
* **BREAKING**: Renamed `Encoding::C_U_LONG` to `Encoding::C_ULONG`.
|
||||
|
||||
|
||||
## 2.0.0-pre.0 - 2022-06-13
|
||||
|
||||
### Added
|
||||
* Added `Encoding::C_LONG` and `Encoding::C_U_LONG` to help with platform
|
||||
compatibility; use these instead of `c_long::ENCODING` and
|
||||
`c_ulong::ENCODING`.
|
||||
* Implement `Encode` and `RefEncode` for `MaybeUninit<T>`, where `T` is
|
||||
properly bound.
|
||||
|
||||
### Changed
|
||||
* **BREAKING**: Sealed the `EncodeArguments` trait.
|
||||
* **BREAKING**: Add type argument to `Encoding::BitField`.
|
||||
|
||||
### Removed
|
||||
* **BREAKING**: Removed `PartialEq` impl between `str` and `Encoding` since it
|
||||
was incorrect (it violated the trait requirements).
|
||||
* **BREAKING**: Removed `Encode` and `RefEncode` implementations for `Pin`
|
||||
since it may not be sound.
|
||||
|
||||
|
||||
## 2.0.0-beta.2 - 2022-01-03
|
||||
|
||||
### Added
|
||||
* Implement `Hash` for `Encoding`.
|
||||
|
||||
### Changed
|
||||
* Improved documentation.
|
||||
|
||||
|
||||
## 2.0.0-beta.1 - 2021-12-22
|
||||
|
||||
### Added
|
||||
* `Encoding::equivalent_to`, `Encoding::equivalent_to_str` and
|
||||
`Encoding::equivalent_to_start_of_str` methods for more precise comparison
|
||||
semantics.
|
||||
* Added `Encode` and `RefEncode` implementations for `Option` function
|
||||
pointers.
|
||||
|
||||
### Changed
|
||||
* Discourage comparing `str` with `Encoding` using `PartialEq`. This trait
|
||||
impl might get removed in a future version.
|
||||
|
||||
|
||||
## 2.0.0-beta.0 - 2021-11-22
|
||||
|
||||
### Added
|
||||
* **BREAKING**: Add `Encoding::LongDouble`, `Encoding::FloatComplex`,
|
||||
`Encoding::DoubleComplex` and `Encoding::LongDoubleComplex`.
|
||||
* Implement `RefEncode` for all number types that implement `Encode` (`bool`,
|
||||
`i8`, `usize`, `f32`, `NonZeroU32`, and so on).
|
||||
* Implement `RefEncode` for `*const c_void` and `*mut c_void` (allowing
|
||||
`void**` in C).
|
||||
* Implement `Encode` and `RefEncode` for `Wrapping<T>`, where `T` is properly
|
||||
bound.
|
||||
|
||||
### Changed
|
||||
* **BREAKING**: Make `Encoding` `#[non_exhaustive]`. This will help us in
|
||||
evolving the API while minimizing further breaking changes.
|
||||
* Discourage using `bool::ENCODING`; use `objc2::Bool::ENCODING` instead.
|
||||
* Discourage using `()::ENCODING` for anything other than as a function return
|
||||
type.
|
||||
|
||||
|
||||
## 2.0.0-alpha.1 - 2021-09-01
|
||||
|
||||
### Added
|
||||
* Improved documentation.
|
||||
* Add `RefEncode` trait, which represents types whoose pointers has an
|
||||
encoding. This means you now only have to implement `RefEncode`, and not
|
||||
both `&Encode` and `&mut Encode`.
|
||||
Additionally, encodings of pointers to pointers (to pointers, and so on) are
|
||||
now supported.
|
||||
* Implement `Encode` for `NonZeroX` and `Option<NonZeroX>` integer types.
|
||||
* Implement `RefEncode` for arrays.
|
||||
* Implement `Encode` and `RefEncode` for (where `T` is properly bound):
|
||||
- `ManuallyDrop<T>`
|
||||
- `Pin<T>`
|
||||
- `NonNull<T>`
|
||||
- `Option<NonNull<T>>`
|
||||
* Add `EncodeArguments` trait, to represent an ordered group of functions
|
||||
arguments, where each argument has an Objective-C type-encoding.
|
||||
Previously in the `objc` crate.
|
||||
* Implement `Encode` and `RefEncode` for some `extern "C" fn` pointers.
|
||||
|
||||
### Removed
|
||||
* **BREAKING**: Removed automatic `*const T: Encode` and `*mut T: Encode`
|
||||
impls when when `&T: Encode` and `&mut T: Encode` was implemented.
|
||||
|
||||
Implement `T: RefEncode` instead!
|
||||
|
||||
|
||||
## 2.0.0-alpha.0 - 2021-09-01
|
||||
|
||||
### Added
|
||||
* Improved documentation.
|
||||
* Support for targets with pointer-width 16
|
||||
* Implement `Encode` for all array lengths using const-generics.
|
||||
* Implement `Encode` for unsized pointer types as well.
|
||||
|
||||
### Changed
|
||||
* **BREAKING**: Forked the project, so it is now available under the name
|
||||
`objc2-encode`.
|
||||
* **BREAKING**: Changed type in `Encoding::BitField` from `u32` to `u8`.
|
||||
* **BREAKING**: Changed type in `Encoding::Array` from `u32` to `usize`.
|
||||
* **BREAKING**: Loosen `'static` bounds on references implementing `Encode`.
|
||||
|
||||
|
||||
## [1.1.0] (`objc-encode` crate) - 2019-10-16
|
||||
|
||||
### Added
|
||||
* Implement `Encode` for arrays with up to 32 elements.
|
||||
|
||||
### Changed
|
||||
* Simplify internal encoding comparison.
|
||||
|
||||
|
||||
## [1.0.0] (`objc-encode` crate) - 2019-03-25
|
||||
|
||||
### Added
|
||||
* Implement `PartialEq` between `Encoding` and `&str`.
|
||||
|
||||
### Changed
|
||||
* **BREAKING**: Make `Encoding` an enum instead of a trait, yielding a vastly
|
||||
different design. This makes use of associated constants.
|
||||
* **BREAKING**: Rename `Encode::CODE` to `Encode::ENCODING`.
|
||||
* Update to Rust 2018.
|
||||
|
||||
### Removed
|
||||
* `libc` dependency.
|
||||
|
||||
|
||||
## [0.0.3] (`objc-encode` crate) - 2017-04-30
|
||||
|
||||
### Fixed
|
||||
* Compilation on versions prior to Rust `1.15`.
|
||||
|
||||
|
||||
## [0.0.2] (`objc-encode` crate) - 2017-02-20
|
||||
|
||||
### Added
|
||||
* **BREAKING**: `Display` requirement for encodings.
|
||||
* Implement `PartialEq` for encodings.
|
||||
* Implement `Encode` for pointers when references do.
|
||||
|
||||
### Fixed
|
||||
* `IndexEncodingsComparator`.
|
||||
* Compilation with older Rust versions.
|
||||
|
||||
|
||||
## [0.0.1] (`objc-encode` crate) - 2017-02-19
|
||||
|
||||
Initial version.
|
||||
|
||||
|
||||
[1.1.0]: https://github.com/madsmtm/objc2/compare/objc-encode-1.0.0...objc-encode-1.1.0
|
||||
[1.0.0]: https://github.com/madsmtm/objc2/compare/objc-encode-0.0.3...objc-encode-1.0.0
|
||||
[0.0.3]: https://github.com/madsmtm/objc2/compare/objc-encode-0.0.2...objc-encode-0.0.3
|
||||
[0.0.2]: https://github.com/madsmtm/objc2/compare/objc-encode-0.0.1...objc-encode-0.0.2
|
||||
[0.0.1]: https://github.com/madsmtm/objc2/releases/tag/objc-encode-0.0.1
|
||||
16
third-party/vendor/objc2-encode/Cargo.lock
generated
vendored
Normal file
16
third-party/vendor/objc2-encode/Cargo.lock
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "objc-sys"
|
||||
version = "0.2.0-beta.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7"
|
||||
|
||||
[[package]]
|
||||
name = "objc2-encode"
|
||||
version = "2.0.0-pre.2"
|
||||
dependencies = [
|
||||
"objc-sys",
|
||||
]
|
||||
83
third-party/vendor/objc2-encode/Cargo.toml
vendored
Normal file
83
third-party/vendor/objc2-encode/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# 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 = "objc2-encode"
|
||||
version = "2.0.0-pre.2"
|
||||
authors = [
|
||||
"Steven Sheldon",
|
||||
"Mads Marquart <mads@marquart.dk>",
|
||||
]
|
||||
description = "Objective-C type-encodings"
|
||||
documentation = "https://docs.rs/objc2-encode/"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"objective-c",
|
||||
"macos",
|
||||
"ios",
|
||||
"encode",
|
||||
]
|
||||
categories = [
|
||||
"development-tools::ffi",
|
||||
"encoding",
|
||||
"no-std",
|
||||
"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.objc-sys]
|
||||
version = "=0.2.0-beta.2"
|
||||
default-features = false
|
||||
|
||||
[features]
|
||||
alloc = ["objc-sys/alloc"]
|
||||
apple = ["objc-sys/apple"]
|
||||
default = [
|
||||
"std",
|
||||
"apple",
|
||||
]
|
||||
gnustep-1-7 = ["objc-sys/gnustep-1-7"]
|
||||
gnustep-1-8 = [
|
||||
"gnustep-1-7",
|
||||
"objc-sys/gnustep-1-8",
|
||||
]
|
||||
gnustep-1-9 = [
|
||||
"gnustep-1-8",
|
||||
"objc-sys/gnustep-1-9",
|
||||
]
|
||||
gnustep-2-0 = [
|
||||
"gnustep-1-9",
|
||||
"objc-sys/gnustep-2-0",
|
||||
]
|
||||
gnustep-2-1 = [
|
||||
"gnustep-2-0",
|
||||
"objc-sys/gnustep-2-1",
|
||||
]
|
||||
std = [
|
||||
"alloc",
|
||||
"objc-sys/std",
|
||||
]
|
||||
unstable-c-unwind = []
|
||||
19
third-party/vendor/objc2-encode/README.md
vendored
Normal file
19
third-party/vendor/objc2-encode/README.md
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# `objc2-encode`
|
||||
|
||||
[](https://crates.io/crates/objc2-encode)
|
||||
[](../LICENSE.txt)
|
||||
[](https://docs.rs/objc2-encode/)
|
||||
[](https://github.com/madsmtm/objc2/actions/workflows/ci.yml)
|
||||
|
||||
Objective-C type-encoding in Rust.
|
||||
|
||||
This crates provides the equivalent of the Objective-C `@encode` directive,
|
||||
and functions for comparing these encodings.
|
||||
|
||||
Additionally, it provides traits for annotating types that has an Objective-C
|
||||
encoding.
|
||||
|
||||
See [the docs](https://docs.rs/objc2-encode/) for a more thorough overview.
|
||||
|
||||
This crate is part of the [`objc2` project](https://github.com/madsmtm/objc2),
|
||||
see that for related crates.
|
||||
41
third-party/vendor/objc2-encode/examples/core_graphics.rs
vendored
Normal file
41
third-party/vendor/objc2-encode/examples/core_graphics.rs
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
use objc2_encode::{Encode, Encoding};
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
type CGFloat = f32;
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
type CGFloat = f64;
|
||||
|
||||
#[repr(C)]
|
||||
struct CGPoint {
|
||||
x: CGFloat,
|
||||
y: CGFloat,
|
||||
}
|
||||
|
||||
unsafe impl Encode for CGPoint {
|
||||
const ENCODING: Encoding = Encoding::Struct("CGPoint", &[CGFloat::ENCODING, CGFloat::ENCODING]);
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct CGSize {
|
||||
width: CGFloat,
|
||||
height: CGFloat,
|
||||
}
|
||||
|
||||
unsafe impl Encode for CGSize {
|
||||
const ENCODING: Encoding = Encoding::Struct("CGSize", &[CGFloat::ENCODING, CGFloat::ENCODING]);
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct CGRect {
|
||||
origin: CGPoint,
|
||||
size: CGSize,
|
||||
}
|
||||
|
||||
unsafe impl Encode for CGRect {
|
||||
const ENCODING: Encoding = Encoding::Struct("CGRect", &[CGPoint::ENCODING, CGSize::ENCODING]);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("{}", CGRect::ENCODING);
|
||||
}
|
||||
25
third-party/vendor/objc2-encode/examples/ns_string.rs
vendored
Normal file
25
third-party/vendor/objc2-encode/examples/ns_string.rs
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
use objc2_encode::{Encode, Encoding, RefEncode};
|
||||
|
||||
/// We don't know the size of NSString, so we can only hold pointers to it.
|
||||
///
|
||||
/// TODO: Use [`extern type`][rfc-1861] when that gets stabilized.
|
||||
///
|
||||
/// [rfc-1861]: https://rust-lang.github.io/rfcs/1861-extern-types.html
|
||||
#[repr(C)]
|
||||
struct NSString {
|
||||
_priv: [u8; 0],
|
||||
}
|
||||
|
||||
/// Implement `RefEncode` for pointers and references to the string.
|
||||
unsafe impl RefEncode for NSString {
|
||||
const ENCODING_REF: Encoding = Encoding::Object;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("{}", <*const NSString>::ENCODING);
|
||||
println!("{}", <*mut NSString>::ENCODING);
|
||||
println!("{}", <&NSString>::ENCODING);
|
||||
println!("{}", <&mut NSString>::ENCODING);
|
||||
println!("{}", Option::<&NSString>::ENCODING);
|
||||
println!("{}", Option::<&mut NSString>::ENCODING);
|
||||
}
|
||||
32
third-party/vendor/objc2-encode/examples/ns_uinteger.rs
vendored
Normal file
32
third-party/vendor/objc2-encode/examples/ns_uinteger.rs
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
//! Implementing `Encode` and `RefEncode` for `NSUInteger`.
|
||||
//!
|
||||
//! Note that in this case `NSUInteger` could actually just be a type alias
|
||||
//! for `usize`, and that's already available under `objc2::ffi::NSUInteger`.
|
||||
use objc2_encode::{Encode, Encoding, RefEncode};
|
||||
|
||||
#[repr(transparent)]
|
||||
struct NSUInteger {
|
||||
_inner: usize,
|
||||
}
|
||||
|
||||
// SAFETY: `NSUInteger` has the same `repr` as `usize`.
|
||||
unsafe impl Encode for NSUInteger {
|
||||
/// Running `@encode(NSUInteger)` gives `Q` on 64-bit systems and `I` on
|
||||
/// 32-bit systems. This corresponds exactly to `usize`, which is also how
|
||||
/// we've defined our struct.
|
||||
const ENCODING: Encoding = usize::ENCODING;
|
||||
}
|
||||
|
||||
// SAFETY: `&NSUInteger` has the same representation as `&usize`.
|
||||
unsafe impl RefEncode for NSUInteger {
|
||||
/// Running `@encode(NSUInteger*)` gives `^Q` on 64-bit systems and `^I`
|
||||
/// on 32-bit systems. So implementing `RefEncode` as a plain pointer is
|
||||
/// correct.
|
||||
const ENCODING_REF: Encoding = Encoding::Pointer(&NSUInteger::ENCODING);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert!(NSUInteger::ENCODING.equivalent_to_str("Q"));
|
||||
assert!(<&NSUInteger>::ENCODING.equivalent_to_str("^Q"));
|
||||
assert!(<&NSUInteger>::ENCODING.equivalent_to_str("r^Q"));
|
||||
}
|
||||
34
third-party/vendor/objc2-encode/examples/opaque_type.rs
vendored
Normal file
34
third-party/vendor/objc2-encode/examples/opaque_type.rs
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
//! Implementing `RefEncode` for `NSDecimal`.
|
||||
use objc2_encode::{Encoding, RefEncode};
|
||||
|
||||
/// We choose in this case to represent `NSDecimal` as an opaque struct
|
||||
/// (and in the future as an `extern type`) because we don't know much
|
||||
/// about the internals.
|
||||
///
|
||||
/// Therefore we do not implement `Encode`, but when implementing `RefEncode`
|
||||
/// the type-encoding still has to be correct.
|
||||
#[repr(C)]
|
||||
struct NSDecimal {
|
||||
_priv: [u8; 0],
|
||||
}
|
||||
|
||||
// SAFETY: `&NSDecimal` is a pointer.
|
||||
unsafe impl RefEncode for NSDecimal {
|
||||
// Running `@encode` on `NSDecimal*` on my 64-bit system gives `^{?=cCCC[38C]}`.
|
||||
const ENCODING_REF: Encoding = Encoding::Pointer(&Encoding::Struct(
|
||||
"?",
|
||||
&[
|
||||
Encoding::Char,
|
||||
Encoding::UChar,
|
||||
Encoding::UChar,
|
||||
Encoding::UChar,
|
||||
Encoding::Array(38, &Encoding::UChar),
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert!(NSDecimal::ENCODING_REF.equivalent_to_str("^{?=cCCC[38C]}"));
|
||||
// Does not compile:
|
||||
// println!("{:?}", NSDecimal::ENCODING);
|
||||
}
|
||||
190
third-party/vendor/objc2-encode/src/__bool.rs
vendored
Normal file
190
third-party/vendor/objc2-encode/src/__bool.rs
vendored
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
//! This belongs in `objc2`, but it is put here to make `EncodeConvert` work
|
||||
//! properly!
|
||||
use core::fmt;
|
||||
|
||||
use crate::{Encode, EncodeConvert, Encoding, RefEncode};
|
||||
|
||||
/// The Objective-C `BOOL` type.
|
||||
///
|
||||
/// This is a thin wrapper-type over [`objc_sys::BOOL`]. It is intended that
|
||||
/// you convert this into a Rust [`bool`] with the [`Bool::as_bool`] method as
|
||||
/// soon as possible.
|
||||
///
|
||||
/// This is FFI-safe and can be used directly with `msg_send!` and `extern`
|
||||
/// functions.
|
||||
///
|
||||
/// Note that this is able to contain more states than `bool` on some
|
||||
/// platforms, but these cases should not be relied on!
|
||||
#[repr(transparent)]
|
||||
// We don't implement comparison traits because they could be implemented with
|
||||
// two slightly different semantics:
|
||||
// - `self.as_bool().cmp(other.as_bool())`
|
||||
// - `self.value.cmp(other.value)`
|
||||
// And it is not immediately clear for users which one was chosen.
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct Bool {
|
||||
value: objc_sys::BOOL,
|
||||
}
|
||||
|
||||
impl Bool {
|
||||
/// The equivalent of [`true`] for Objective-C's `BOOL` type.
|
||||
pub const YES: Self = Self::from_raw(objc_sys::YES);
|
||||
|
||||
/// The equivalent of [`false`] for Objective-C's `BOOL` type.
|
||||
pub const NO: Self = Self::from_raw(objc_sys::NO);
|
||||
|
||||
/// Creates an Objective-C boolean from a Rust boolean.
|
||||
#[inline]
|
||||
pub const fn new(value: bool) -> Self {
|
||||
// true as BOOL => 1 (YES)
|
||||
// false as BOOL => 0 (NO)
|
||||
let value = value as objc_sys::BOOL;
|
||||
Self { value }
|
||||
}
|
||||
|
||||
/// Creates this from a boolean value received from a raw Objective-C API.
|
||||
#[inline]
|
||||
pub const fn from_raw(value: objc_sys::BOOL) -> Self {
|
||||
Self { value }
|
||||
}
|
||||
|
||||
/// Retrieves the inner [`objc_sys::BOOL`] boolean type, to be used in raw
|
||||
/// Objective-C APIs.
|
||||
#[inline]
|
||||
pub const fn as_raw(self) -> objc_sys::BOOL {
|
||||
self.value
|
||||
}
|
||||
|
||||
/// Returns `true` if `self` is [`NO`][Self::NO].
|
||||
///
|
||||
/// You should prefer using [`as_bool`][Self::as_bool].
|
||||
#[inline]
|
||||
pub const fn is_false(self) -> bool {
|
||||
!self.as_bool()
|
||||
}
|
||||
|
||||
/// Returns `true` if `self` is not [`NO`][Self::NO].
|
||||
///
|
||||
/// You should prefer using [`as_bool`][Self::as_bool].
|
||||
#[inline]
|
||||
pub const fn is_true(self) -> bool {
|
||||
self.as_bool()
|
||||
}
|
||||
|
||||
/// Converts this into the [`bool`] equivalent.
|
||||
#[inline]
|
||||
pub const fn as_bool(self) -> bool {
|
||||
// Always compare with 0 (NO)
|
||||
// This is what happens with the `!` operator / when using `if` in C.
|
||||
self.value != objc_sys::NO
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for Bool {
|
||||
#[inline]
|
||||
fn from(b: bool) -> Bool {
|
||||
Bool::new(b)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Bool> for bool {
|
||||
#[inline]
|
||||
fn from(b: Bool) -> bool {
|
||||
b.as_bool()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Bool {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(if self.as_bool() { "YES" } else { "NO" })
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: `Bool` is `repr(transparent)`.
|
||||
unsafe impl Encode for Bool {
|
||||
// i8::__ENCODING == Encoding::Char
|
||||
// u8::__ENCODING == Encoding::UChar
|
||||
// bool::__ENCODING == Encoding::Bool
|
||||
// i32::__ENCODING == Encoding::Int
|
||||
const ENCODING: Encoding = objc_sys::BOOL::__ENCODING;
|
||||
}
|
||||
|
||||
// Note that we shouldn't delegate to `BOOL`'s `ENCODING_REF` since `BOOL` is
|
||||
// sometimes `i8`/`u8`, and their `ENCODING_REF`s are `Encoding::String`,
|
||||
// which is incorrect for `BOOL`:
|
||||
//
|
||||
// ```objc
|
||||
// @encode(BOOL); // -> "c", "C" or "B"
|
||||
// @encode(BOOL*); // -> "^c", "^C" or "^B"
|
||||
// @encode(char); // -> "c" or "C"
|
||||
// @encode(char*); // -> "*"
|
||||
// ```
|
||||
unsafe impl RefEncode for Bool {
|
||||
const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use alloc::format;
|
||||
|
||||
#[test]
|
||||
fn test_basic() {
|
||||
let b = Bool::new(true);
|
||||
assert!(b.as_bool());
|
||||
assert!(b.is_true());
|
||||
assert!(!b.is_false());
|
||||
assert!(bool::from(b));
|
||||
assert_eq!(b.as_raw() as usize, 1);
|
||||
|
||||
let b = Bool::new(false);
|
||||
assert!(!b.as_bool());
|
||||
assert!(!b.is_true());
|
||||
assert!(b.is_false());
|
||||
assert!(!bool::from(b));
|
||||
assert_eq!(b.as_raw() as usize, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_associated_constants() {
|
||||
let b = Bool::YES;
|
||||
assert!(b.as_bool());
|
||||
assert!(b.is_true());
|
||||
assert_eq!(b.as_raw() as usize, 1);
|
||||
|
||||
let b = Bool::NO;
|
||||
assert!(!b.as_bool());
|
||||
assert!(b.is_false());
|
||||
assert_eq!(b.as_raw() as usize, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_impls() {
|
||||
let b: Bool = Default::default();
|
||||
assert!(!b.as_bool());
|
||||
assert!(b.is_false());
|
||||
|
||||
assert!(Bool::from(true).as_bool());
|
||||
assert!(Bool::from(true).is_true());
|
||||
assert!(Bool::from(false).is_false());
|
||||
|
||||
assert!(Bool::from(true).is_true());
|
||||
assert!(Bool::from(false).is_false());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_debug() {
|
||||
assert_eq!(format!("{:?}", Bool::from(true)), "YES");
|
||||
assert_eq!(format!("{:?}", Bool::from(false)), "NO");
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Test on platform where we know the type of BOOL
|
||||
#[cfg(all(feature = "apple", target_os = "macos", target_arch = "x86_64"))]
|
||||
fn test_outside_normal() {
|
||||
let b = Bool::from_raw(42);
|
||||
assert!(b.is_true());
|
||||
assert!(!b.is_false());
|
||||
assert_eq!(b.as_raw(), 42);
|
||||
}
|
||||
}
|
||||
841
third-party/vendor/objc2-encode/src/encode.rs
vendored
Normal file
841
third-party/vendor/objc2-encode/src/encode.rs
vendored
Normal file
|
|
@ -0,0 +1,841 @@
|
|||
use core::ffi::c_void;
|
||||
use core::mem::{ManuallyDrop, MaybeUninit};
|
||||
use core::num::{
|
||||
NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU16, NonZeroU32,
|
||||
NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping,
|
||||
};
|
||||
use core::ptr::NonNull;
|
||||
use core::sync::atomic;
|
||||
|
||||
use crate::Encoding;
|
||||
use crate::__bool::Bool;
|
||||
|
||||
/// Types that have an Objective-C type-encoding.
|
||||
///
|
||||
/// Usually you will want to implement [`RefEncode`] as well.
|
||||
///
|
||||
/// If your type is an opaque type you should not need to implement this;
|
||||
/// there you will only need [`RefEncode`].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The type must be FFI-safe, meaning a C-compatible `repr` (`repr(C)`,
|
||||
/// `repr(u8)`, `repr(transparent)` where the inner types are C-compatible,
|
||||
/// and so on). See the [nomicon on other `repr`s][reprs].
|
||||
///
|
||||
/// Objective-C will make assumptions about the type (like its size, alignment
|
||||
/// and ABI) from its encoding, so the implementer must verify that the
|
||||
/// encoding is accurate.
|
||||
///
|
||||
/// Concretely, [`Self::ENCODING`] must match the result of running `@encode`
|
||||
/// in Objective-C with the type in question.
|
||||
///
|
||||
/// You should also beware of having [`Drop`] types implement this, since when
|
||||
/// passed to Objective-C via. `objc2::msg_send!` their destructor will not be
|
||||
/// called!
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Implementing for a struct:
|
||||
///
|
||||
/// ```
|
||||
/// # use objc2_encode::{Encode, Encoding, RefEncode};
|
||||
/// # use core::ffi::c_void;
|
||||
/// #
|
||||
/// #[repr(C)]
|
||||
/// struct MyType {
|
||||
/// a: i32,
|
||||
/// b: f64,
|
||||
/// c: *const c_void,
|
||||
/// }
|
||||
///
|
||||
/// unsafe impl Encode for MyType {
|
||||
/// const ENCODING: Encoding = Encoding::Struct(
|
||||
/// // The name of the type that Objective-C sees.
|
||||
/// "MyType",
|
||||
/// &[
|
||||
/// // Delegate to field's implementations.
|
||||
/// // The order is the same as in the definition.
|
||||
/// i32::ENCODING,
|
||||
/// f64::ENCODING,
|
||||
/// <*const c_void>::ENCODING,
|
||||
/// ],
|
||||
/// );
|
||||
/// }
|
||||
///
|
||||
/// // Note: You would also implement `RefEncode` for this type.
|
||||
/// ```
|
||||
///
|
||||
/// [reprs]: https://doc.rust-lang.org/nomicon/other-reprs.html
|
||||
pub unsafe trait Encode {
|
||||
/// The Objective-C type-encoding for this type.
|
||||
const ENCODING: Encoding;
|
||||
}
|
||||
|
||||
/// Types whoose references has an Objective-C type-encoding.
|
||||
///
|
||||
/// Implementing this for `T` provides [`Encode`] implementations for:
|
||||
/// - `*const T`
|
||||
/// - `*mut T`
|
||||
/// - `&T`
|
||||
/// - `&mut T`
|
||||
/// - `NonNull<T>`
|
||||
/// - `Option<&T>`
|
||||
/// - `Option<&mut T>`
|
||||
/// - `Option<NonNull<T>>`
|
||||
///
|
||||
/// # Reasoning behind this trait's existence
|
||||
///
|
||||
/// External crates cannot implement [`Encode`] for pointers or [`Option`]s
|
||||
/// containing references, so instead, they can implement this trait.
|
||||
/// Additionally it would be very cumbersome if every type had to implement
|
||||
/// [`Encode`] for all possible pointer types.
|
||||
///
|
||||
/// Finally, having this trait allows for much cleaner generic code that need
|
||||
/// to represent types that can be encoded as pointers.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// References to the object must be FFI-safe.
|
||||
///
|
||||
/// See the nomicon entry on [representing opaque structs][opaque] for
|
||||
/// information on how to represent objects that you don't know the layout of
|
||||
/// (or use `extern type` ([RFC-1861]) if you're using nightly).
|
||||
///
|
||||
/// Objective-C will make assumptions about the type (like its size, alignment
|
||||
/// and ABI) from its encoding, so the implementer must verify that the
|
||||
/// encoding is accurate.
|
||||
///
|
||||
/// Concretely, [`Self::ENCODING_REF`] must match the result of running
|
||||
/// `@encode` in Objective-C with a pointer to the type in question.
|
||||
///
|
||||
/// [opaque]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
|
||||
/// [RFC-1861]: https://rust-lang.github.io/rfcs/1861-extern-types.html
|
||||
pub unsafe trait RefEncode {
|
||||
/// The Objective-C type-encoding for a reference of this type.
|
||||
///
|
||||
/// Should be one of [`Encoding::Object`], [`Encoding::Block`],
|
||||
/// [`Encoding::Class`], [`Encoding::Pointer`], [`Encoding::Sel`] or
|
||||
/// [`Encoding::Unknown`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// This is usually implemented either as an object pointer:
|
||||
/// ```
|
||||
/// # use objc2_encode::{Encoding, RefEncode};
|
||||
/// # #[repr(C)]
|
||||
/// # struct MyObject {
|
||||
/// # _priv: [u8; 0],
|
||||
/// # }
|
||||
/// # unsafe impl RefEncode for MyObject {
|
||||
/// const ENCODING_REF: Encoding = Encoding::Object;
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// Or as a pointer to the type, delegating the rest to the [`Encode`]
|
||||
/// implementation:
|
||||
/// ```
|
||||
/// # use objc2_encode::{Encode, Encoding, RefEncode};
|
||||
/// # #[repr(transparent)]
|
||||
/// # struct MyType(i32);
|
||||
/// # unsafe impl Encode for MyType {
|
||||
/// # const ENCODING: Encoding = i32::ENCODING;
|
||||
/// # }
|
||||
/// # unsafe impl RefEncode for MyType {
|
||||
/// const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
|
||||
/// # }
|
||||
/// ```
|
||||
const ENCODING_REF: Encoding;
|
||||
}
|
||||
|
||||
// TODO: Implement for `PhantomData` and `PhantomPinned`?
|
||||
|
||||
/// Simple helper for implementing [`Encode`].
|
||||
macro_rules! encode_impls {
|
||||
($($t:ty => $e:ident,)*) => ($(
|
||||
unsafe impl Encode for $t {
|
||||
const ENCODING: Encoding = Encoding::$e;
|
||||
}
|
||||
)*);
|
||||
}
|
||||
|
||||
encode_impls!(
|
||||
i8 => Char,
|
||||
i16 => Short,
|
||||
i32 => Int,
|
||||
i64 => LongLong,
|
||||
u8 => UChar,
|
||||
u16 => UShort,
|
||||
u32 => UInt,
|
||||
u64 => ULongLong,
|
||||
f32 => Float,
|
||||
f64 => Double,
|
||||
|
||||
// TODO: i128 & u128
|
||||
// https://github.com/rust-lang/rust/issues/54341
|
||||
);
|
||||
|
||||
// TODO: Structs in core::arch?
|
||||
|
||||
/// To allow usage as the return type of generic functions.
|
||||
///
|
||||
/// You should not rely on this encoding to exist for any other purpose (since
|
||||
/// `()` is not FFI-safe)!
|
||||
// TODO: Figure out a way to remove this - maybe with a `EncodeReturn` trait?
|
||||
unsafe impl Encode for () {
|
||||
const ENCODING: Encoding = Encoding::Void;
|
||||
}
|
||||
|
||||
// UI tests of this is too brittle.
|
||||
#[cfg(doctest)]
|
||||
/// ```
|
||||
/// use objc2_encode::Encode;
|
||||
/// <()>::ENCODING; // TODO: Make this fail as well
|
||||
/// ```
|
||||
/// ```should_fail
|
||||
/// use core::ffi::c_void;
|
||||
/// use objc2_encode::Encode;
|
||||
/// <c_void>::ENCODING;
|
||||
/// ```
|
||||
/// ```should_fail
|
||||
/// use objc2_encode::Encode;
|
||||
/// <*const ()>::ENCODING;
|
||||
/// ```
|
||||
/// ```should_fail
|
||||
/// use core::ffi::c_void;
|
||||
/// use objc2_encode::Encode;
|
||||
/// <&c_void>::ENCODING;
|
||||
/// ```
|
||||
extern "C" {}
|
||||
|
||||
macro_rules! encode_impls_size {
|
||||
($($t:ty => ($t16:ty, $t32:ty, $t64:ty),)*) => ($(
|
||||
#[doc = concat!("The encoding of [`", stringify!($t), "`] varies based on the target pointer width.")]
|
||||
unsafe impl Encode for $t {
|
||||
#[cfg(target_pointer_width = "16")]
|
||||
const ENCODING: Encoding = <$t16>::ENCODING;
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
const ENCODING: Encoding = <$t32>::ENCODING;
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const ENCODING: Encoding = <$t64>::ENCODING;
|
||||
}
|
||||
)*);
|
||||
}
|
||||
|
||||
encode_impls_size!(
|
||||
isize => (i16, i32, i64),
|
||||
usize => (u16, u32, u64),
|
||||
);
|
||||
|
||||
/// Simple helper for implementing [`RefEncode`].
|
||||
macro_rules! pointer_refencode_impl {
|
||||
($($t:ty),*) => ($(
|
||||
unsafe impl RefEncode for $t {
|
||||
const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
|
||||
}
|
||||
)*);
|
||||
}
|
||||
|
||||
pointer_refencode_impl!(i16, i32, i64, isize, u16, u32, u64, usize, f32, f64);
|
||||
|
||||
/// Pointers to [`i8`] use the special [`Encoding::String`] encoding.
|
||||
unsafe impl RefEncode for i8 {
|
||||
const ENCODING_REF: Encoding = Encoding::String;
|
||||
}
|
||||
|
||||
/// Pointers to [`u8`] use the special [`Encoding::String`] encoding.
|
||||
unsafe impl RefEncode for u8 {
|
||||
const ENCODING_REF: Encoding = Encoding::String;
|
||||
}
|
||||
|
||||
/// Simple helper for implementing [`Encode`] for nonzero integer types.
|
||||
macro_rules! encode_impls_nonzero {
|
||||
($($nonzero:ident => $type:ty,)*) => ($(
|
||||
unsafe impl Encode for $nonzero {
|
||||
const ENCODING: Encoding = <$type>::ENCODING;
|
||||
}
|
||||
|
||||
unsafe impl Encode for Option<$nonzero> {
|
||||
const ENCODING: Encoding = <$type>::ENCODING;
|
||||
}
|
||||
|
||||
unsafe impl RefEncode for $nonzero {
|
||||
const ENCODING_REF: Encoding = <$type>::ENCODING_REF;
|
||||
}
|
||||
|
||||
unsafe impl RefEncode for Option<$nonzero> {
|
||||
const ENCODING_REF: Encoding = <$type>::ENCODING_REF;
|
||||
}
|
||||
)*);
|
||||
}
|
||||
|
||||
encode_impls_nonzero!(
|
||||
NonZeroI8 => i8,
|
||||
NonZeroI16 => i16,
|
||||
NonZeroI32 => i32,
|
||||
NonZeroI64 => i64,
|
||||
NonZeroIsize => isize,
|
||||
NonZeroU8 => u8,
|
||||
NonZeroU16 => u16,
|
||||
NonZeroU32 => u32,
|
||||
NonZeroU64 => u64,
|
||||
NonZeroUsize => usize,
|
||||
);
|
||||
|
||||
/// Simple helper for implementing for atomic types.
|
||||
macro_rules! encode_atomic_impls {
|
||||
($(
|
||||
$(#[$m:meta])*
|
||||
$atomic:ident => $type:ty,
|
||||
)*) => ($(
|
||||
// SAFETY: C11 `_Atomic` types use compatible synchronization
|
||||
// primitives, and the atomic type is guaranteed to have the same
|
||||
// in-memory representation as the underlying type.
|
||||
$(#[$m])*
|
||||
unsafe impl Encode for atomic::$atomic {
|
||||
const ENCODING: Encoding = Encoding::Atomic(&<$type>::ENCODING);
|
||||
}
|
||||
|
||||
$(#[$m])*
|
||||
unsafe impl RefEncode for atomic::$atomic {
|
||||
const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
|
||||
}
|
||||
)*);
|
||||
}
|
||||
|
||||
encode_atomic_impls!(
|
||||
#[cfg(target_has_atomic = "8")]
|
||||
AtomicI8 => i8,
|
||||
#[cfg(target_has_atomic = "8")]
|
||||
AtomicU8 => u8,
|
||||
|
||||
#[cfg(target_has_atomic = "16")]
|
||||
AtomicI16 => i16,
|
||||
#[cfg(target_has_atomic = "16")]
|
||||
AtomicU16 => u16,
|
||||
|
||||
#[cfg(target_has_atomic = "32")]
|
||||
AtomicI32 => i32,
|
||||
#[cfg(target_has_atomic = "32")]
|
||||
AtomicU32 => u32,
|
||||
|
||||
#[cfg(target_has_atomic = "64")]
|
||||
AtomicI64 => i64,
|
||||
#[cfg(target_has_atomic = "64")]
|
||||
AtomicU64 => u64,
|
||||
|
||||
// TODO
|
||||
// #[cfg(target_has_atomic = "128")]
|
||||
// AtomicI128 => i128,
|
||||
// #[cfg(target_has_atomic = "128")]
|
||||
// AtomicU128 => u128,
|
||||
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
AtomicIsize => isize,
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
AtomicUsize => usize,
|
||||
);
|
||||
|
||||
// SAFETY: Guaranteed to have the same in-memory representation as `*mut T`.
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
unsafe impl<T: RefEncode> Encode for atomic::AtomicPtr<T> {
|
||||
const ENCODING: Encoding = Encoding::Atomic(&T::ENCODING_REF);
|
||||
}
|
||||
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
unsafe impl<T: RefEncode> RefEncode for atomic::AtomicPtr<T> {
|
||||
const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
|
||||
}
|
||||
|
||||
/// [`Encode`] is implemented manually for `*const c_void`, instead of
|
||||
/// implementing [`RefEncode`], to discourage creating `&c_void`.
|
||||
unsafe impl Encode for *const c_void {
|
||||
const ENCODING: Encoding = Encoding::Pointer(&Encoding::Void);
|
||||
}
|
||||
|
||||
unsafe impl RefEncode for *const c_void {
|
||||
const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
|
||||
}
|
||||
|
||||
/// [`Encode`] is implemented manually for `*mut c_void`, instead of
|
||||
/// implementing [`RefEncode`], to discourage creating `&mut c_void`.
|
||||
unsafe impl Encode for *mut c_void {
|
||||
const ENCODING: Encoding = Encoding::Pointer(&Encoding::Void);
|
||||
}
|
||||
|
||||
unsafe impl RefEncode for *mut c_void {
|
||||
const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
|
||||
}
|
||||
|
||||
unsafe impl<T: Encode, const LENGTH: usize> Encode for [T; LENGTH] {
|
||||
const ENCODING: Encoding = Encoding::Array(LENGTH, &T::ENCODING);
|
||||
}
|
||||
|
||||
unsafe impl<T: Encode, const LENGTH: usize> RefEncode for [T; LENGTH] {
|
||||
const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
|
||||
}
|
||||
|
||||
macro_rules! encode_impls_transparent {
|
||||
($($t:ident<T $(: ?$b:ident)?>,)*) => ($(
|
||||
unsafe impl<T: Encode $(+ ?$b)?> Encode for $t<T> {
|
||||
const ENCODING: Encoding = T::ENCODING;
|
||||
}
|
||||
|
||||
unsafe impl<T: RefEncode $(+ ?$b)?> RefEncode for $t<T> {
|
||||
const ENCODING_REF: Encoding = T::ENCODING_REF;
|
||||
}
|
||||
)*);
|
||||
}
|
||||
|
||||
encode_impls_transparent! {
|
||||
// SAFETY: Guaranteed to have the same layout as `T`, and is subject to
|
||||
// the same layout optimizations as `T`.
|
||||
// TODO: With specialization: `impl Encode for ManuallyDrop<Box<T>>`
|
||||
ManuallyDrop<T: ?Sized>,
|
||||
|
||||
// The fact that this has `repr(no_niche)` has no effect on us, since we
|
||||
// don't implement `Encode` generically over `Option`.
|
||||
// (e.g. an `Option<UnsafeCell<&u8>>` impl is not available).
|
||||
// The inner field is not public, so may not be stable.
|
||||
// TODO: UnsafeCell<T>,
|
||||
|
||||
// The inner field is not public, so may not be safe.
|
||||
// TODO: Pin<T>,
|
||||
|
||||
// SAFETY: Guaranteed to have the same size, alignment, and ABI as `T`.
|
||||
MaybeUninit<T>,
|
||||
|
||||
// SAFETY: Guaranteed to have the same layout and ABI as `T`.
|
||||
Wrapping<T>,
|
||||
|
||||
// It might have requirements that would disourage this impl?
|
||||
// TODO: Cell<T>
|
||||
|
||||
// TODO: Types that need to be made repr(transparent) first:
|
||||
// - core::cell::Ref?
|
||||
// - core::cell::RefCell?
|
||||
// - core::cell::RefMut?
|
||||
// - core::panic::AssertUnwindSafe<T>
|
||||
// TODO: core::num::Saturating when that is stabilized
|
||||
// TODO: core::cmp::Reverse?
|
||||
}
|
||||
|
||||
/// Helper for implementing `Encode`/`RefEncode` for pointers to types that
|
||||
/// implement `RefEncode`.
|
||||
///
|
||||
/// Using `?Sized` is safe here because we delegate to other implementations
|
||||
/// (which will verify that the implementation is safe for the unsized type).
|
||||
macro_rules! encode_pointer_impls {
|
||||
(unsafe impl<T: RefEncode> $x:ident for Pointer<T> {
|
||||
const $c:ident = $e:expr;
|
||||
}) => (
|
||||
unsafe impl<T: RefEncode + ?Sized> $x for *const T {
|
||||
const $c: Encoding = $e;
|
||||
}
|
||||
|
||||
unsafe impl<T: RefEncode + ?Sized> $x for *mut T {
|
||||
const $c: Encoding = $e;
|
||||
}
|
||||
|
||||
unsafe impl<'a, T: RefEncode + ?Sized> $x for &'a T {
|
||||
const $c: Encoding = $e;
|
||||
}
|
||||
|
||||
unsafe impl<'a, T: RefEncode + ?Sized> $x for &'a mut T {
|
||||
const $c: Encoding = $e;
|
||||
}
|
||||
|
||||
unsafe impl<T: RefEncode + ?Sized> $x for NonNull<T> {
|
||||
const $c: Encoding = $e;
|
||||
}
|
||||
|
||||
unsafe impl<'a, T: RefEncode + ?Sized> $x for Option<&'a T> {
|
||||
const $c: Encoding = $e;
|
||||
}
|
||||
|
||||
unsafe impl<'a, T: RefEncode + ?Sized> $x for Option<&'a mut T> {
|
||||
const $c: Encoding = $e;
|
||||
}
|
||||
|
||||
unsafe impl<T: RefEncode + ?Sized> $x for Option<NonNull<T>> {
|
||||
const $c: Encoding = $e;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Implement `Encode` for types that are `RefEncode`.
|
||||
//
|
||||
// This allows users to implement `Encode` for custom types that have a
|
||||
// specific encoding as a pointer, instead of having to implement it for each
|
||||
// pointer-like type in turn.
|
||||
encode_pointer_impls!(
|
||||
unsafe impl<T: RefEncode> Encode for Pointer<T> {
|
||||
const ENCODING = T::ENCODING_REF;
|
||||
}
|
||||
);
|
||||
|
||||
// Implement `RefEncode` for pointers to types that are `RefEncode`.
|
||||
//
|
||||
// This implements `Encode` for pointers to pointers (to pointers, and so on),
|
||||
// which would otherwise be very cumbersome to do manually.
|
||||
encode_pointer_impls!(
|
||||
unsafe impl<T: RefEncode> RefEncode for Pointer<T> {
|
||||
const ENCODING_REF = Encoding::Pointer(&T::ENCODING_REF);
|
||||
}
|
||||
);
|
||||
|
||||
/// Helper for implementing [`Encode`]/[`RefEncode`] for function pointers
|
||||
/// whoose arguments implement [`Encode`].
|
||||
///
|
||||
/// Ideally we'd implement it for all function pointers, but due to coherence
|
||||
/// issues, see <https://github.com/rust-lang/rust/issues/56105>, function
|
||||
/// pointers that are higher-ranked over lifetimes don't get implemented.
|
||||
///
|
||||
/// We could fix it by adding those impls and allowing `coherence_leak_check`,
|
||||
/// but it would have to be done for _all_ references, `Option<&T>` and such as
|
||||
/// well. So trying to do it quickly requires generating a polynomial amount of
|
||||
/// implementations, which IMO is overkill for such a small issue.
|
||||
///
|
||||
/// Using `?Sized` is probably not safe here because C functions can only take
|
||||
/// and return items with a known size.
|
||||
macro_rules! encode_fn_pointer_impl {
|
||||
(@ $FnTy: ty, $($Arg: ident),*) => {
|
||||
unsafe impl<Ret: Encode, $($Arg: Encode),*> Encode for $FnTy {
|
||||
const ENCODING: Encoding = Encoding::Pointer(&Encoding::Unknown);
|
||||
}
|
||||
unsafe impl<Ret: Encode, $($Arg: Encode),*> RefEncode for $FnTy {
|
||||
const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
|
||||
}
|
||||
|
||||
unsafe impl<Ret: Encode, $($Arg: Encode),*> Encode for Option<$FnTy> {
|
||||
const ENCODING: Encoding = Encoding::Pointer(&Encoding::Unknown);
|
||||
}
|
||||
unsafe impl<Ret: Encode, $($Arg: Encode),*> RefEncode for Option<$FnTy> {
|
||||
const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
|
||||
}
|
||||
};
|
||||
(# $abi:literal; $($Arg: ident),+) => {
|
||||
// Normal functions
|
||||
encode_fn_pointer_impl!(@ extern $abi fn($($Arg),+) -> Ret, $($Arg),+ );
|
||||
encode_fn_pointer_impl!(@ unsafe extern $abi fn($($Arg),+) -> Ret, $($Arg),+ );
|
||||
// Variadic functions
|
||||
encode_fn_pointer_impl!(@ extern $abi fn($($Arg),+ , ...) -> Ret, $($Arg),+ );
|
||||
encode_fn_pointer_impl!(@ unsafe extern $abi fn($($Arg),+ , ...) -> Ret, $($Arg),+ );
|
||||
};
|
||||
(# $abi:literal; ) => {
|
||||
// No variadic functions with 0 parameters
|
||||
encode_fn_pointer_impl!(@ extern $abi fn() -> Ret, );
|
||||
encode_fn_pointer_impl!(@ unsafe extern $abi fn() -> Ret, );
|
||||
};
|
||||
($($Arg: ident),*) => {
|
||||
encode_fn_pointer_impl!(# "C"; $($Arg),*);
|
||||
#[cfg(feature = "unstable-c-unwind")]
|
||||
encode_fn_pointer_impl!(# "C-unwind"; $($Arg),*);
|
||||
};
|
||||
}
|
||||
|
||||
encode_fn_pointer_impl!();
|
||||
encode_fn_pointer_impl!(A);
|
||||
encode_fn_pointer_impl!(A, B);
|
||||
encode_fn_pointer_impl!(A, B, C);
|
||||
encode_fn_pointer_impl!(A, B, C, D);
|
||||
encode_fn_pointer_impl!(A, B, C, D, E);
|
||||
encode_fn_pointer_impl!(A, B, C, D, E, F);
|
||||
encode_fn_pointer_impl!(A, B, C, D, E, F, G);
|
||||
encode_fn_pointer_impl!(A, B, C, D, E, F, G, H);
|
||||
encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I);
|
||||
encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J);
|
||||
encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K);
|
||||
encode_fn_pointer_impl!(A, B, C, D, E, F, G, H, I, J, K, L);
|
||||
|
||||
mod convert_private {
|
||||
use super::*;
|
||||
|
||||
pub trait Sealed {}
|
||||
impl<T: Encode> Sealed for T {}
|
||||
impl Sealed for bool {}
|
||||
}
|
||||
|
||||
/// Represents types that can easily be converted to/from an [`Encode`] type.
|
||||
///
|
||||
/// This is implemented specially for [`bool`] to allow using that as
|
||||
/// Objective-C `BOOL`, where it would otherwise not be allowed (since they
|
||||
/// are not ABI compatible).
|
||||
///
|
||||
/// This is mostly an implementation detail, and hence the trait is sealed.
|
||||
/// Open an issue if you know a use-case where this restrition should be
|
||||
/// lifted!
|
||||
pub trait EncodeConvert: convert_private::Sealed {
|
||||
/// The inner type that this can be converted to and from.
|
||||
#[doc(hidden)]
|
||||
type __Inner: Encode;
|
||||
|
||||
/// The actual encoding this type has.
|
||||
#[doc(hidden)]
|
||||
const __ENCODING: Encoding;
|
||||
|
||||
#[doc(hidden)]
|
||||
fn __from_inner(inner: Self::__Inner) -> Self;
|
||||
|
||||
#[doc(hidden)]
|
||||
fn __into_inner(self) -> Self::__Inner;
|
||||
}
|
||||
|
||||
impl<T: Encode> EncodeConvert for T {
|
||||
type __Inner = Self;
|
||||
const __ENCODING: Encoding = Self::ENCODING;
|
||||
|
||||
#[inline]
|
||||
fn __from_inner(inner: Self::__Inner) -> Self {
|
||||
inner
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn __into_inner(self) -> Self::__Inner {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeConvert for bool {
|
||||
type __Inner = Bool;
|
||||
const __ENCODING: Encoding = Encoding::Bool;
|
||||
|
||||
#[inline]
|
||||
fn __from_inner(inner: Self::__Inner) -> Self {
|
||||
inner.as_bool()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn __into_inner(self) -> Self::__Inner {
|
||||
Bool::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
mod args_private {
|
||||
pub trait Sealed {}
|
||||
}
|
||||
|
||||
/// Types that represent an ordered group of function arguments, where each
|
||||
/// argument has an Objective-C type-encoding, or can be converted from one.
|
||||
///
|
||||
/// This is implemented for tuples of up to 12 arguments, where each argument
|
||||
/// implements [`EncodeConvert`]. It is primarily used to make generic code
|
||||
/// a bit easier.
|
||||
///
|
||||
/// Note that tuples themselves don't implement [`Encode`] directly, because
|
||||
/// they're not FFI-safe!
|
||||
///
|
||||
/// 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!
|
||||
///
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// You cannot rely on this trait for ensuring that the arguments all
|
||||
/// are [`Encode`], since they may only implement [`EncodeConvert`]. Use your
|
||||
/// own trait and add [`Encode`] bounds on that.
|
||||
pub unsafe trait EncodeArguments: args_private::Sealed {
|
||||
/// The encodings for the arguments.
|
||||
const ENCODINGS: &'static [Encoding];
|
||||
}
|
||||
|
||||
macro_rules! encode_args_impl {
|
||||
($($Arg: ident),*) => {
|
||||
impl<$($Arg: EncodeConvert),*> args_private::Sealed for ($($Arg,)*) {}
|
||||
|
||||
unsafe impl<$($Arg: EncodeConvert),*> EncodeArguments for ($($Arg,)*) {
|
||||
const ENCODINGS: &'static [Encoding] = &[
|
||||
// T::__Inner::ENCODING => T::ENCODING
|
||||
// bool::__Inner::ENCODING => Bool::ENCODING
|
||||
$($Arg::__Inner::ENCODING),*
|
||||
];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
encode_args_impl!();
|
||||
encode_args_impl!(A);
|
||||
encode_args_impl!(A, B);
|
||||
encode_args_impl!(A, B, C);
|
||||
encode_args_impl!(A, B, C, D);
|
||||
encode_args_impl!(A, B, C, D, E);
|
||||
encode_args_impl!(A, B, C, D, E, F);
|
||||
encode_args_impl!(A, B, C, D, E, F, G);
|
||||
encode_args_impl!(A, B, C, D, E, F, G, H);
|
||||
encode_args_impl!(A, B, C, D, E, F, G, H, I);
|
||||
encode_args_impl!(A, B, C, D, E, F, G, H, I, J);
|
||||
encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K);
|
||||
encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K, L);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use core::any::TypeId;
|
||||
use core::sync::atomic::*;
|
||||
|
||||
#[test]
|
||||
fn test_c_string() {
|
||||
assert_eq!(i8::ENCODING, Encoding::Char);
|
||||
assert_eq!(u8::ENCODING, Encoding::UChar);
|
||||
|
||||
assert_eq!(<*const i8>::ENCODING, Encoding::String);
|
||||
assert_eq!(<&u8>::ENCODING, Encoding::String);
|
||||
assert_eq!(i8::ENCODING_REF, Encoding::String);
|
||||
assert_eq!(i8::ENCODING_REF, Encoding::String);
|
||||
|
||||
assert_eq!(
|
||||
<*const *const i8>::ENCODING,
|
||||
Encoding::Pointer(&Encoding::String)
|
||||
);
|
||||
assert_eq!(<&&u8>::ENCODING, Encoding::Pointer(&Encoding::String));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_i32() {
|
||||
assert_eq!(i32::ENCODING, Encoding::Int);
|
||||
assert_eq!(<&i32>::ENCODING, Encoding::Pointer(&Encoding::Int));
|
||||
assert_eq!(
|
||||
<&&i32>::ENCODING,
|
||||
Encoding::Pointer(&Encoding::Pointer(&Encoding::Int))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_atomic() {
|
||||
assert_eq!(AtomicI32::ENCODING, Encoding::Atomic(&Encoding::Int));
|
||||
assert_eq!(
|
||||
AtomicI32::ENCODING_REF,
|
||||
Encoding::Pointer(&Encoding::Atomic(&Encoding::Int))
|
||||
);
|
||||
assert_eq!(
|
||||
AtomicPtr::<i32>::ENCODING,
|
||||
Encoding::Atomic(&Encoding::Pointer(&Encoding::Int))
|
||||
);
|
||||
|
||||
assert_eq!(AtomicI8::ENCODING, Encoding::Atomic(&Encoding::Char));
|
||||
assert_eq!(
|
||||
AtomicI8::ENCODING_REF,
|
||||
Encoding::Pointer(&Encoding::Atomic(&Encoding::Char))
|
||||
);
|
||||
assert_eq!(
|
||||
AtomicPtr::<i8>::ENCODING,
|
||||
Encoding::Atomic(&Encoding::String)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_void() {
|
||||
// TODO: Remove this
|
||||
assert_eq!(<()>::ENCODING, Encoding::Void);
|
||||
assert_eq!(
|
||||
<*const c_void>::ENCODING,
|
||||
Encoding::Pointer(&Encoding::Void)
|
||||
);
|
||||
assert_eq!(
|
||||
<&*const c_void>::ENCODING,
|
||||
Encoding::Pointer(&Encoding::Pointer(&Encoding::Void))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transparent() {
|
||||
assert_eq!(<ManuallyDrop<u8>>::ENCODING, u8::ENCODING);
|
||||
assert_eq!(<ManuallyDrop<&u8>>::ENCODING, u8::ENCODING_REF);
|
||||
assert_eq!(<ManuallyDrop<Option<&u8>>>::ENCODING, u8::ENCODING_REF);
|
||||
assert_eq!(<&ManuallyDrop<Option<&u8>>>::ENCODING, <&&u8>::ENCODING);
|
||||
|
||||
// assert_eq!(<UnsafeCell<u8>>::ENCODING, u8::ENCODING);
|
||||
// assert_eq!(<Pin<u8>>::ENCODING, u8::ENCODING);
|
||||
assert_eq!(<MaybeUninit<u8>>::ENCODING, u8::ENCODING);
|
||||
assert_eq!(<Wrapping<u8>>::ENCODING, u8::ENCODING);
|
||||
|
||||
// Shouldn't compile
|
||||
// assert_eq!(<Option<UnsafeCell<&u8>>>::ENCODING, <&u8>::ENCODING);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extern_fn_pointer() {
|
||||
assert_eq!(
|
||||
<extern "C" fn()>::ENCODING,
|
||||
Encoding::Pointer(&Encoding::Unknown)
|
||||
);
|
||||
assert_eq!(
|
||||
<extern "C" fn(x: ()) -> ()>::ENCODING,
|
||||
Encoding::Pointer(&Encoding::Unknown)
|
||||
);
|
||||
assert_eq!(
|
||||
<Option<unsafe extern "C" fn()>>::ENCODING,
|
||||
Encoding::Pointer(&Encoding::Unknown)
|
||||
);
|
||||
#[cfg(feature = "unstable-c-unwind")]
|
||||
assert_eq!(
|
||||
<extern "C-unwind" fn()>::ENCODING,
|
||||
Encoding::Pointer(&Encoding::Unknown)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extern_fn_pointer_elided_lifetime() {
|
||||
fn impls_encode<T: Encode>(_x: T) {}
|
||||
|
||||
extern "C" fn my_fn1(_x: &i32) {}
|
||||
extern "C" fn my_fn2(_x: &i32, _y: &u8) {}
|
||||
extern "C" fn my_fn3(x: &u8) -> &u8 {
|
||||
x
|
||||
}
|
||||
extern "C" fn my_fn4<'a, 'b>(x: &'a u8, _y: &'b i32) -> &'a u8 {
|
||||
x
|
||||
}
|
||||
|
||||
impls_encode(my_fn1 as extern "C" fn(_));
|
||||
impls_encode(my_fn2 as extern "C" fn(_, _));
|
||||
impls_encode(my_fn3 as extern "C" fn(_) -> _);
|
||||
impls_encode(my_fn4 as extern "C" fn(_, _) -> _);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_normally_noop() {
|
||||
assert_eq!(
|
||||
TypeId::of::<<i32 as EncodeConvert>::__Inner>(),
|
||||
TypeId::of::<i32>()
|
||||
);
|
||||
assert_eq!(<i32 as EncodeConvert>::__from_inner(42), 42);
|
||||
assert_eq!(42i32.__into_inner(), 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_i8() {
|
||||
assert_eq!(
|
||||
TypeId::of::<<i8 as EncodeConvert>::__Inner>(),
|
||||
TypeId::of::<i8>()
|
||||
);
|
||||
assert_eq!(<i8 as EncodeConvert>::__from_inner(-3), -3);
|
||||
assert_eq!((-3i32).__into_inner(), -3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_bool() {
|
||||
assert!(!<bool as EncodeConvert>::__from_inner(Bool::NO));
|
||||
assert!(<bool as EncodeConvert>::__from_inner(Bool::YES));
|
||||
|
||||
assert!(!false.__into_inner().as_bool());
|
||||
assert!(true.__into_inner().as_bool());
|
||||
assert_eq!(bool::__ENCODING, Encoding::Bool);
|
||||
|
||||
assert_eq!(
|
||||
<bool as EncodeConvert>::__Inner::__ENCODING,
|
||||
<bool as EncodeConvert>::__Inner::ENCODING
|
||||
);
|
||||
|
||||
#[cfg(all(feature = "apple", target_os = "macos", target_arch = "x86_64"))]
|
||||
assert_eq!(<bool as EncodeConvert>::__Inner::ENCODING, Encoding::Char);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encode_arguments() {
|
||||
assert!(<()>::ENCODINGS.is_empty());
|
||||
assert_eq!(<(i8,)>::ENCODINGS, &[i8::ENCODING]);
|
||||
assert_eq!(<(i8, u32)>::ENCODINGS, &[i8::ENCODING, u32::ENCODING]);
|
||||
}
|
||||
}
|
||||
594
third-party/vendor/objc2-encode/src/encoding.rs
vendored
Normal file
594
third-party/vendor/objc2-encode/src/encoding.rs
vendored
Normal file
|
|
@ -0,0 +1,594 @@
|
|||
use core::fmt;
|
||||
|
||||
use crate::helper::{Helper, NestingLevel};
|
||||
use crate::parse;
|
||||
|
||||
/// An Objective-C type-encoding.
|
||||
///
|
||||
/// Can be retrieved in Objective-C for a type `T` using the `@encode(T)`
|
||||
/// directive.
|
||||
/// ```objc
|
||||
/// NSLog(@"Encoding of NSException: %s", @encode(NSException));
|
||||
/// ```
|
||||
///
|
||||
/// The [`Display`][`fmt::Display`] implementation converts the [`Encoding`]
|
||||
/// into its string representation, that the the `@encode` directive would
|
||||
/// return. This can be used conveniently through the `to_string` method:
|
||||
///
|
||||
/// ```
|
||||
/// use objc2_encode::Encoding;
|
||||
/// assert_eq!(Encoding::Int.to_string(), "i");
|
||||
/// ```
|
||||
///
|
||||
/// For more information on the string value of an encoding, see [Apple's
|
||||
/// documentation][ocrtTypeEncodings].
|
||||
///
|
||||
/// [ocrtTypeEncodings]: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Comparing an encoding to a string from the Objective-C runtime:
|
||||
///
|
||||
/// ```
|
||||
/// use objc2_encode::Encoding;
|
||||
/// assert!(Encoding::Array(10, &Encoding::FloatComplex).equivalent_to_str("[10jf]"));
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
// See <https://en.cppreference.com/w/c/language/type>
|
||||
#[non_exhaustive] // Maybe we're missing some encodings?
|
||||
pub enum Encoding {
|
||||
/// A C `char`. Corresponds to the `c` code.
|
||||
Char,
|
||||
/// A C `short`. Corresponds to the `s` code.
|
||||
Short,
|
||||
/// A C `int`. Corresponds to the `i` code.
|
||||
Int,
|
||||
/// A C `long`. Corresponds to the `l` code.
|
||||
///
|
||||
/// This is treated as a 32-bit quantity in 64-bit programs.
|
||||
// TODO: What does that mean??
|
||||
Long,
|
||||
/// A C `long long`. Corresponds to the `q` code.
|
||||
LongLong,
|
||||
/// A C `unsigned char`. Corresponds to the `C` code.
|
||||
UChar,
|
||||
/// A C `unsigned short`. Corresponds to the `S` code.
|
||||
UShort,
|
||||
/// A C `unsigned int`. Corresponds to the `I` code.
|
||||
UInt,
|
||||
/// A C `unsigned long`. Corresponds to the `L` code.
|
||||
ULong,
|
||||
/// A C `unsigned long long`. Corresponds to the `Q` code.
|
||||
ULongLong,
|
||||
/// A C `float`. Corresponds to the `f` code.
|
||||
Float,
|
||||
/// A C `double`. Corresponds to the `d` code.
|
||||
Double,
|
||||
/// A C `long double`. Corresponds to the `D` code.
|
||||
LongDouble,
|
||||
/// A C `float _Complex`. Corresponds to the `jf` code.
|
||||
FloatComplex,
|
||||
/// A C `_Complex` or `double _Complex`. Corresponds to the `jd` code.
|
||||
DoubleComplex,
|
||||
/// A C `long double _Complex`. Corresponds to the `jD` code.
|
||||
LongDoubleComplex,
|
||||
// TODO: Complex(&Encoding) ???
|
||||
/// A C++ `bool` / C99 `_Bool`. Corresponds to the `B` code.
|
||||
Bool,
|
||||
/// A C `void`. Corresponds to the `v` code.
|
||||
Void,
|
||||
/// A C `char *`. Corresponds to the `*` code.
|
||||
String,
|
||||
/// An Objective-C object (`id`). Corresponds to the `@` code.
|
||||
Object,
|
||||
/// An Objective-C block. Corresponds to the `@?` code.
|
||||
Block,
|
||||
/// An Objective-C class (`Class`). Corresponds to the `#` code.
|
||||
Class,
|
||||
/// An Objective-C selector (`SEL`). Corresponds to the `:` code.
|
||||
Sel,
|
||||
/// An unknown type. Corresponds to the `?` code.
|
||||
///
|
||||
/// This is usually used to encode functions.
|
||||
Unknown,
|
||||
/// A bitfield with the given number of bits, and the given type.
|
||||
///
|
||||
/// The type is not currently used, but may be in the future for better
|
||||
/// compatibility with Objective-C runtimes.
|
||||
///
|
||||
/// Corresponds to the `b num` code.
|
||||
BitField(u8, &'static Encoding),
|
||||
/// A pointer to the given type.
|
||||
///
|
||||
/// Corresponds to the `^ type` code.
|
||||
Pointer(&'static Encoding),
|
||||
/// A C11 [`_Atomic`] type.
|
||||
///
|
||||
/// Corresponds to the `A type` code. Not all encodings are possible in
|
||||
/// this.
|
||||
///
|
||||
/// [`_Atomic`]: https://en.cppreference.com/w/c/language/atomic
|
||||
Atomic(&'static Encoding),
|
||||
/// An array with the given length and type.
|
||||
///
|
||||
/// Corresponds to the `[len type]` code.
|
||||
Array(usize, &'static Encoding),
|
||||
/// A struct with the given name and fields.
|
||||
///
|
||||
/// The order of the fields must match the order of the order in this.
|
||||
///
|
||||
/// It is not uncommon for the name to be `"?"`.
|
||||
///
|
||||
/// Corresponds to the `{name=fields...}` code.
|
||||
Struct(&'static str, &'static [Encoding]),
|
||||
/// A union with the given name and fields.
|
||||
///
|
||||
/// The order of the fields must match the order of the order in this.
|
||||
///
|
||||
/// Corresponds to the `(name=fields...)` code.
|
||||
Union(&'static str, &'static [Encoding]),
|
||||
// "Vector" types have the '!' encoding, but are not implemented in clang
|
||||
|
||||
// TODO: `t` and `T` codes for i128 and u128?
|
||||
}
|
||||
|
||||
impl Encoding {
|
||||
/// The encoding of [`c_long`](`std::os::raw::c_long`).
|
||||
///
|
||||
/// Ideally the encoding of `long` would just be the same as `int` when
|
||||
/// it's 32 bits wide and the same as `long long` when it is 64 bits wide;
|
||||
/// then `c_long::ENCODING` would just work.
|
||||
///
|
||||
/// Unfortunately, `long` have a different encoding than `int` when it is
|
||||
/// 32 bits wide; the [`l`][`Encoding::Long`] encoding.
|
||||
pub const C_LONG: Self = {
|
||||
// Alternative: `mem::size_of::<c_long>() == 4`
|
||||
// That would exactly match what `clang` does:
|
||||
// https://github.com/llvm/llvm-project/blob/release/13.x/clang/lib/AST/ASTContext.cpp#L7245
|
||||
if cfg!(any(target_pointer_width = "32", windows)) {
|
||||
// @encode(long) = 'l'
|
||||
Self::Long
|
||||
} else {
|
||||
// @encode(long) = 'q'
|
||||
Self::LongLong
|
||||
}
|
||||
};
|
||||
|
||||
/// The encoding of [`c_ulong`](`std::os::raw::c_ulong`).
|
||||
///
|
||||
/// See [`Encoding::C_LONG`] for explanation.
|
||||
pub const C_ULONG: Self = {
|
||||
if cfg!(any(target_pointer_width = "32", windows)) {
|
||||
// @encode(unsigned long) = 'L'
|
||||
Self::ULong
|
||||
} else {
|
||||
// @encode(unsigned long) = 'Q'
|
||||
Self::ULongLong
|
||||
}
|
||||
};
|
||||
|
||||
/// Check if one encoding is equivalent to another.
|
||||
///
|
||||
/// Currently, equivalence testing requires that the encodings are equal,
|
||||
/// except for qualifiers. This may be changed in the future to e.g.
|
||||
/// ignore struct names, to allow structs behind multiple pointers to be
|
||||
/// considered equivalent, or similar changes that may be required because
|
||||
/// of limitations in Objective-C compiler implementations.
|
||||
///
|
||||
/// For example, you should not rely on two equivalent encodings to have
|
||||
/// the same size or ABI - that is provided on a best-effort basis.
|
||||
pub fn equivalent_to(&self, other: &Self) -> bool {
|
||||
equivalent_to(self, other, NestingLevel::new())
|
||||
}
|
||||
|
||||
/// Check if an encoding is equivalent to the given string representation.
|
||||
///
|
||||
/// See [`Encoding::equivalent_to`] for details about the meaning of
|
||||
/// "equivalence".
|
||||
pub fn equivalent_to_str(&self, s: &str) -> bool {
|
||||
// if the given encoding can be successfully removed from the start
|
||||
// and an empty string remains, they were fully equivalent!
|
||||
if let Some(res) = self.equivalent_to_start_of_str(s) {
|
||||
res.is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if an encoding is equivalent to the start of the given string
|
||||
/// representation.
|
||||
///
|
||||
/// If it is equivalent, the remaining part of the string is returned.
|
||||
/// Otherwise this returns [`None`].
|
||||
///
|
||||
/// See [`Encoding::equivalent_to`] for details about the meaning of
|
||||
/// "equivalence".
|
||||
pub fn equivalent_to_start_of_str<'a>(&self, s: &'a str) -> Option<&'a str> {
|
||||
// strip leading qualifiers
|
||||
let s = s.trim_start_matches(parse::QUALIFIERS);
|
||||
|
||||
// TODO: Allow missing/"?" names in structs and unions?
|
||||
|
||||
parse::rm_enc_prefix(s, self, NestingLevel::new())
|
||||
}
|
||||
}
|
||||
|
||||
fn equivalent_to(enc1: &Encoding, enc2: &Encoding, level: NestingLevel) -> bool {
|
||||
// Note: Ideally `Block` and sequence of `Object, Unknown` in struct
|
||||
// should compare equal, but we don't bother since in practice a plain
|
||||
// `Unknown` will never appear.
|
||||
use Helper::*;
|
||||
match (Helper::new(enc1), Helper::new(enc2)) {
|
||||
(Primitive(p1), Primitive(p2)) => p1 == p2,
|
||||
(BitField(b1, type1), BitField(b2, type2)) => {
|
||||
b1 == b2 && equivalent_to(type1, type2, level.bitfield())
|
||||
}
|
||||
(Indirection(kind1, t1), Indirection(kind2, t2)) => {
|
||||
kind1 == kind2 && equivalent_to(t1, t2, level.indirection(kind1))
|
||||
}
|
||||
(Array(len1, item1), Array(len2, item2)) => {
|
||||
len1 == len2 && equivalent_to(item1, item2, level.array())
|
||||
}
|
||||
(Container(kind1, name1, fields1), Container(kind2, name2, fields2)) => {
|
||||
if kind1 != kind2 {
|
||||
return false;
|
||||
}
|
||||
if name1 != name2 {
|
||||
return false;
|
||||
}
|
||||
if let Some(level) = level.container() {
|
||||
if fields1.len() != fields2.len() {
|
||||
return false;
|
||||
}
|
||||
for (field1, field2) in fields1.iter().zip(fields2.iter()) {
|
||||
if !equivalent_to(field1, field2, level) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
(_, _) => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn display_fmt(this: &Encoding, f: &mut fmt::Formatter<'_>, level: NestingLevel) -> fmt::Result {
|
||||
use Helper::*;
|
||||
match Helper::new(this) {
|
||||
Primitive(primitive) => f.write_str(primitive.to_str()),
|
||||
BitField(b, _type) => {
|
||||
// TODO: Use the type on GNUStep (nesting level?)
|
||||
write!(f, "b{}", b)
|
||||
}
|
||||
Indirection(kind, t) => {
|
||||
write!(f, "{}", kind.prefix())?;
|
||||
display_fmt(t, f, level.indirection(kind))
|
||||
}
|
||||
Array(len, item) => {
|
||||
write!(f, "[")?;
|
||||
write!(f, "{}", len)?;
|
||||
display_fmt(item, f, level.array())?;
|
||||
write!(f, "]")
|
||||
}
|
||||
Container(kind, name, fields) => {
|
||||
write!(f, "{}", kind.start())?;
|
||||
write!(f, "{}", name)?;
|
||||
if let Some(level) = level.container() {
|
||||
write!(f, "=")?;
|
||||
for field in fields {
|
||||
display_fmt(field, f, level)?;
|
||||
}
|
||||
}
|
||||
write!(f, "{}", kind.end())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Formats this [`Encoding`] in a similar way that the `@encode` directive
|
||||
/// would ordinarily do.
|
||||
///
|
||||
/// You should not rely on the output of this to be stable across versions. It
|
||||
/// may change if found to be required to be compatible with exisiting
|
||||
/// Objective-C compilers.
|
||||
impl fmt::Display for Encoding {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
display_fmt(self, f, NestingLevel::new())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Encoding;
|
||||
use crate::helper::NestingLevel;
|
||||
use crate::static_str::{static_encoding_str_array, static_encoding_str_len};
|
||||
use alloc::string::ToString;
|
||||
|
||||
fn send_sync<T: Send + Sync>() {}
|
||||
|
||||
#[test]
|
||||
fn test_send_sync() {
|
||||
send_sync::<Encoding>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smoke() {
|
||||
assert!(Encoding::Short.equivalent_to_str("s"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn qualifiers() {
|
||||
assert!(Encoding::Void.equivalent_to_str("v"));
|
||||
assert!(Encoding::Void.equivalent_to_str("Vv"));
|
||||
assert!(Encoding::String.equivalent_to_str("*"));
|
||||
assert!(Encoding::String.equivalent_to_str("r*"));
|
||||
}
|
||||
|
||||
macro_rules! assert_enc {
|
||||
($(
|
||||
fn $name:ident() {
|
||||
$encoding:expr;
|
||||
$(
|
||||
~$equivalent_encoding:expr;
|
||||
)*
|
||||
$(
|
||||
!$not_encoding:expr;
|
||||
)*
|
||||
$string:literal;
|
||||
$(
|
||||
~$equivalent_string:expr;
|
||||
)*
|
||||
$(
|
||||
!$not_string:literal;
|
||||
)*
|
||||
}
|
||||
)+) => {$(
|
||||
#[test]
|
||||
fn $name() {
|
||||
const E: Encoding = $encoding;
|
||||
|
||||
// Check PartialEq
|
||||
assert_eq!(E, E);
|
||||
|
||||
// Check Display
|
||||
assert_eq!(E.to_string(), $string);
|
||||
|
||||
// Check equivalence comparisons
|
||||
assert!(E.equivalent_to(&E));
|
||||
assert!(E.equivalent_to_str($string));
|
||||
assert_eq!(E.equivalent_to_start_of_str(concat!($string, "xyz")), Some("xyz"));
|
||||
$(
|
||||
assert!(E.equivalent_to(&$equivalent_encoding));
|
||||
assert!(E.equivalent_to_str(&$equivalent_encoding.to_string()));
|
||||
)*
|
||||
$(
|
||||
assert!(E.equivalent_to_str($equivalent_string));
|
||||
)*
|
||||
|
||||
// Negative checks
|
||||
$(
|
||||
assert_ne!(E, $not_encoding);
|
||||
assert!(!E.equivalent_to(&$not_encoding));
|
||||
assert!(!E.equivalent_to_str(&$not_encoding.to_string()));
|
||||
)*
|
||||
$(
|
||||
assert!(!E.equivalent_to_str(&$not_string));
|
||||
)*
|
||||
|
||||
// Check static str
|
||||
const STATIC_ENCODING_DATA: [u8; static_encoding_str_len(&E, NestingLevel::new())] = static_encoding_str_array(&E, NestingLevel::new());
|
||||
const STATIC_ENCODING_STR: &str = unsafe { core::str::from_utf8_unchecked(&STATIC_ENCODING_DATA) };
|
||||
assert_eq!(STATIC_ENCODING_STR, $string);
|
||||
}
|
||||
)+};
|
||||
}
|
||||
|
||||
assert_enc! {
|
||||
fn int() {
|
||||
Encoding::Int;
|
||||
!Encoding::Char;
|
||||
"i";
|
||||
}
|
||||
|
||||
fn char() {
|
||||
Encoding::Char;
|
||||
!Encoding::Int;
|
||||
"c";
|
||||
// Qualifiers
|
||||
~"rc";
|
||||
~"nc";
|
||||
~"Nc";
|
||||
~"oc";
|
||||
~"Oc";
|
||||
~"Rc";
|
||||
~"Vc";
|
||||
|
||||
!"ri";
|
||||
}
|
||||
|
||||
fn block() {
|
||||
Encoding::Block;
|
||||
"@?";
|
||||
}
|
||||
|
||||
fn object() {
|
||||
Encoding::Object;
|
||||
!Encoding::Block;
|
||||
"@";
|
||||
!"@?";
|
||||
}
|
||||
|
||||
fn unknown() {
|
||||
Encoding::Unknown;
|
||||
!Encoding::Block;
|
||||
"?";
|
||||
}
|
||||
|
||||
// Note: A raw `?` cannot happen in practice, since functions can only
|
||||
// be accessed through pointers, and that will yield `^?`
|
||||
fn object_unknown_in_struct() {
|
||||
Encoding::Struct("S", &[Encoding::Block, Encoding::Object, Encoding::Unknown]);
|
||||
"{S=@?@?}";
|
||||
}
|
||||
|
||||
fn double() {
|
||||
Encoding::Double;
|
||||
"d";
|
||||
}
|
||||
|
||||
fn bitfield() {
|
||||
Encoding::BitField(32, &Encoding::Int);
|
||||
!Encoding::Int;
|
||||
!Encoding::BitField(33, &Encoding::Int);
|
||||
"b32";
|
||||
!"b32a";
|
||||
!"b";
|
||||
!"b-32";
|
||||
}
|
||||
|
||||
fn atomic() {
|
||||
Encoding::Atomic(&Encoding::Int);
|
||||
!Encoding::Pointer(&Encoding::Int);
|
||||
!Encoding::Atomic(&Encoding::Char);
|
||||
!Encoding::Atomic(&Encoding::Atomic(&Encoding::Int));
|
||||
"Ai";
|
||||
}
|
||||
|
||||
fn atomic_string() {
|
||||
Encoding::Atomic(&Encoding::String);
|
||||
"A*";
|
||||
}
|
||||
|
||||
fn pointer() {
|
||||
Encoding::Pointer(&Encoding::Int);
|
||||
!Encoding::Atomic(&Encoding::Int);
|
||||
!Encoding::Pointer(&Encoding::Char);
|
||||
!Encoding::Pointer(&Encoding::Pointer(&Encoding::Int));
|
||||
"^i";
|
||||
}
|
||||
|
||||
fn array() {
|
||||
Encoding::Array(12, &Encoding::Int);
|
||||
!Encoding::Int;
|
||||
!Encoding::Array(11, &Encoding::Int);
|
||||
!Encoding::Array(12, &Encoding::Char);
|
||||
"[12i]";
|
||||
!"[12i";
|
||||
}
|
||||
|
||||
fn struct_() {
|
||||
Encoding::Struct("SomeStruct", &[Encoding::Char, Encoding::Int]);
|
||||
!Encoding::Union("SomeStruct", &[Encoding::Char, Encoding::Int]);
|
||||
!Encoding::Int;
|
||||
!Encoding::Struct("SomeStruct", &[Encoding::Int]);
|
||||
!Encoding::Struct("SomeStruct", &[Encoding::Char, Encoding::Int, Encoding::Int]);
|
||||
!Encoding::Struct("SomeStruct", &[Encoding::Int, Encoding::Char]);
|
||||
!Encoding::Struct("AnotherName", &[Encoding::Char, Encoding::Int]);
|
||||
"{SomeStruct=ci}";
|
||||
!"{SomeStruct=ci";
|
||||
!"{SomeStruct}";
|
||||
!"{SomeStruct=}";
|
||||
}
|
||||
|
||||
fn struct_unicode() {
|
||||
Encoding::Struct("☃", &[Encoding::Char]);
|
||||
"{☃=c}";
|
||||
}
|
||||
|
||||
fn pointer_struct() {
|
||||
Encoding::Pointer(&Encoding::Struct("SomeStruct", &[Encoding::Char, Encoding::Int]));
|
||||
!Encoding::Pointer(&Encoding::Struct("SomeStruct", &[Encoding::Int, Encoding::Char]));
|
||||
!Encoding::Pointer(&Encoding::Struct("AnotherName", &[Encoding::Char, Encoding::Int]));
|
||||
"^{SomeStruct=ci}";
|
||||
!"^{SomeStruct=ci";
|
||||
!"^{SomeStruct}";
|
||||
!"^{SomeStruct=}";
|
||||
}
|
||||
|
||||
fn pointer_pointer_struct() {
|
||||
Encoding::Pointer(&Encoding::Pointer(&Encoding::Struct("SomeStruct", &[Encoding::Char, Encoding::Int])));
|
||||
~Encoding::Pointer(&Encoding::Pointer(&Encoding::Struct("SomeStruct", &[Encoding::Int, Encoding::Char])));
|
||||
!Encoding::Pointer(&Encoding::Pointer(&Encoding::Struct("AnotherName", &[Encoding::Char, Encoding::Int])));
|
||||
"^^{SomeStruct}";
|
||||
!"^^{SomeStruct=ci}";
|
||||
!"^^{SomeStruct=ii}";
|
||||
!"^^{SomeStruct=ci";
|
||||
!"^^{SomeStruct=}";
|
||||
}
|
||||
|
||||
fn atomic_struct() {
|
||||
Encoding::Atomic(&Encoding::Struct("SomeStruct", &[Encoding::Char, Encoding::Int]));
|
||||
~Encoding::Atomic(&Encoding::Struct("SomeStruct", &[Encoding::Int, Encoding::Char]));
|
||||
!Encoding::Atomic(&Encoding::Struct("AnotherName", &[Encoding::Char, Encoding::Int]));
|
||||
"A{SomeStruct}";
|
||||
!"A{SomeStruct=ci}";
|
||||
!"A{SomeStruct=ci";
|
||||
!"A{SomeStruct=}";
|
||||
}
|
||||
|
||||
fn empty_struct() {
|
||||
Encoding::Struct("SomeStruct", &[]);
|
||||
"{SomeStruct=}";
|
||||
// TODO: Unsure about this
|
||||
!"{SomeStruct}";
|
||||
}
|
||||
|
||||
fn union_() {
|
||||
Encoding::Union("Onion", &[Encoding::Char, Encoding::Int]);
|
||||
!Encoding::Struct("Onion", &[Encoding::Char, Encoding::Int]);
|
||||
!Encoding::Int;
|
||||
!Encoding::Union("Onion", &[Encoding::Int, Encoding::Char]);
|
||||
!Encoding::Union("AnotherUnion", &[Encoding::Char, Encoding::Int]);
|
||||
"(Onion=ci)";
|
||||
!"(Onion=ci";
|
||||
}
|
||||
|
||||
fn nested() {
|
||||
Encoding::Struct(
|
||||
"A",
|
||||
&[
|
||||
Encoding::Struct("B", &[Encoding::Int]),
|
||||
Encoding::Pointer(&Encoding::Struct("C", &[Encoding::Double])),
|
||||
Encoding::Char,
|
||||
],
|
||||
);
|
||||
~Encoding::Struct(
|
||||
"A",
|
||||
&[
|
||||
Encoding::Struct("B", &[Encoding::Int]),
|
||||
Encoding::Pointer(&Encoding::Struct("C", &[])),
|
||||
Encoding::Char,
|
||||
],
|
||||
);
|
||||
"{A={B=i}^{C}c}";
|
||||
!"{A={B=i}^{C=d}c}";
|
||||
!"{A={B=i}^{C=i}c}";
|
||||
!"{A={B=i}^{C=d}c";
|
||||
}
|
||||
|
||||
fn nested_pointer() {
|
||||
Encoding::Pointer(&Encoding::Struct(
|
||||
"A",
|
||||
&[
|
||||
Encoding::Struct("B", &[Encoding::Int]),
|
||||
Encoding::Pointer(&Encoding::Struct("C", &[Encoding::Double])),
|
||||
],
|
||||
));
|
||||
"^{A={B=i}^{C}}";
|
||||
!"^{A={B}^{C}}";
|
||||
!"^{A={B=i}^{C=d}}";
|
||||
}
|
||||
|
||||
fn various() {
|
||||
Encoding::Struct(
|
||||
"abc",
|
||||
&[
|
||||
Encoding::Pointer(&Encoding::Array(8, &Encoding::Bool)),
|
||||
Encoding::Union("def", &[Encoding::Block]),
|
||||
Encoding::Pointer(&Encoding::Pointer(&Encoding::BitField(255, &Encoding::Int))),
|
||||
Encoding::Unknown,
|
||||
]
|
||||
);
|
||||
"{abc=^[8B](def=@?)^^b255?}";
|
||||
}
|
||||
}
|
||||
}
|
||||
205
third-party/vendor/objc2-encode/src/helper.rs
vendored
Normal file
205
third-party/vendor/objc2-encode/src/helper.rs
vendored
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
use crate::Encoding;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub(crate) enum NestingLevel {
|
||||
Top,
|
||||
Within,
|
||||
Bottom,
|
||||
}
|
||||
|
||||
impl NestingLevel {
|
||||
pub(crate) const fn new() -> Self {
|
||||
Self::Top
|
||||
}
|
||||
|
||||
pub(crate) const fn bitfield(self) -> Self {
|
||||
// TODO: Is this correct?
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) const fn indirection(self, kind: IndirectionKind) -> Self {
|
||||
match kind {
|
||||
// Move all the way down
|
||||
IndirectionKind::Atomic => Self::Bottom,
|
||||
// Move one step down
|
||||
IndirectionKind::Pointer => match self {
|
||||
Self::Top => Self::Within,
|
||||
Self::Bottom | Self::Within => Self::Bottom,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn array(self) -> Self {
|
||||
// TODO: Is this correct?
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) const fn container(self) -> Option<Self> {
|
||||
match self {
|
||||
// Move one step down, and output
|
||||
Self::Top => Some(Self::Within),
|
||||
// Output
|
||||
Self::Within => Some(Self::Within),
|
||||
// Don't output
|
||||
Self::Bottom => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
#[non_exhaustive]
|
||||
pub(crate) enum Primitive {
|
||||
Char,
|
||||
Short,
|
||||
Int,
|
||||
Long,
|
||||
LongLong,
|
||||
UChar,
|
||||
UShort,
|
||||
UInt,
|
||||
ULong,
|
||||
ULongLong,
|
||||
Float,
|
||||
Double,
|
||||
LongDouble,
|
||||
FloatComplex,
|
||||
DoubleComplex,
|
||||
LongDoubleComplex,
|
||||
Bool,
|
||||
Void,
|
||||
String,
|
||||
Object,
|
||||
Block,
|
||||
Class,
|
||||
Sel,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl Primitive {
|
||||
pub(crate) const fn to_str(self) -> &'static str {
|
||||
use Primitive::*;
|
||||
match self {
|
||||
Char => "c",
|
||||
Short => "s",
|
||||
Int => "i",
|
||||
Long => "l",
|
||||
LongLong => "q",
|
||||
UChar => "C",
|
||||
UShort => "S",
|
||||
UInt => "I",
|
||||
ULong => "L",
|
||||
ULongLong => "Q",
|
||||
Float => "f",
|
||||
Double => "d",
|
||||
LongDouble => "D",
|
||||
FloatComplex => "jf",
|
||||
DoubleComplex => "jd",
|
||||
LongDoubleComplex => "jD",
|
||||
Bool => "B",
|
||||
Void => "v",
|
||||
String => "*",
|
||||
Object => "@",
|
||||
Block => "@?",
|
||||
Class => "#",
|
||||
Sel => ":",
|
||||
Unknown => "?",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub(crate) enum IndirectionKind {
|
||||
Atomic,
|
||||
Pointer,
|
||||
}
|
||||
|
||||
impl IndirectionKind {
|
||||
pub(crate) const fn prefix(self) -> char {
|
||||
self.prefix_byte() as char
|
||||
}
|
||||
|
||||
pub(crate) const fn prefix_byte(self) -> u8 {
|
||||
match self {
|
||||
Self::Atomic => b'A',
|
||||
Self::Pointer => b'^',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub(crate) enum ContainerKind {
|
||||
Struct,
|
||||
Union,
|
||||
}
|
||||
|
||||
impl ContainerKind {
|
||||
pub(crate) const fn start(self) -> char {
|
||||
self.start_byte() as char
|
||||
}
|
||||
|
||||
pub(crate) const fn end(self) -> char {
|
||||
self.end_byte() as char
|
||||
}
|
||||
|
||||
pub(crate) const fn start_byte(self) -> u8 {
|
||||
match self {
|
||||
Self::Struct => b'{',
|
||||
Self::Union => b'(',
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn end_byte(self) -> u8 {
|
||||
match self {
|
||||
Self::Struct => b'}',
|
||||
Self::Union => b')',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
#[non_exhaustive]
|
||||
pub(crate) enum Helper<'a> {
|
||||
Primitive(Primitive),
|
||||
BitField(u8, &'a Encoding),
|
||||
Indirection(IndirectionKind, &'a Encoding),
|
||||
Array(usize, &'a Encoding),
|
||||
Container(ContainerKind, &'a str, &'a [Encoding]),
|
||||
}
|
||||
|
||||
impl<'a> Helper<'a> {
|
||||
pub(crate) const fn new(encoding: &'a Encoding) -> Self {
|
||||
use Encoding::*;
|
||||
match encoding {
|
||||
Char => Self::Primitive(Primitive::Char),
|
||||
Short => Self::Primitive(Primitive::Short),
|
||||
Int => Self::Primitive(Primitive::Int),
|
||||
Long => Self::Primitive(Primitive::Long),
|
||||
LongLong => Self::Primitive(Primitive::LongLong),
|
||||
UChar => Self::Primitive(Primitive::UChar),
|
||||
UShort => Self::Primitive(Primitive::UShort),
|
||||
UInt => Self::Primitive(Primitive::UInt),
|
||||
ULong => Self::Primitive(Primitive::ULong),
|
||||
ULongLong => Self::Primitive(Primitive::ULongLong),
|
||||
Float => Self::Primitive(Primitive::Float),
|
||||
Double => Self::Primitive(Primitive::Double),
|
||||
LongDouble => Self::Primitive(Primitive::LongDouble),
|
||||
FloatComplex => Self::Primitive(Primitive::FloatComplex),
|
||||
DoubleComplex => Self::Primitive(Primitive::DoubleComplex),
|
||||
LongDoubleComplex => Self::Primitive(Primitive::LongDoubleComplex),
|
||||
Bool => Self::Primitive(Primitive::Bool),
|
||||
Void => Self::Primitive(Primitive::Void),
|
||||
String => Self::Primitive(Primitive::String),
|
||||
Object => Self::Primitive(Primitive::Object),
|
||||
Block => Self::Primitive(Primitive::Block),
|
||||
Class => Self::Primitive(Primitive::Class),
|
||||
Sel => Self::Primitive(Primitive::Sel),
|
||||
Unknown => Self::Primitive(Primitive::Unknown),
|
||||
BitField(b, t) => Self::BitField(*b, t),
|
||||
Pointer(t) => Self::Indirection(IndirectionKind::Pointer, t),
|
||||
Atomic(t) => Self::Indirection(IndirectionKind::Atomic, t),
|
||||
Array(len, item) => Self::Array(*len, item),
|
||||
Struct(name, fields) => Self::Container(ContainerKind::Struct, name, fields),
|
||||
Union(name, members) => Self::Container(ContainerKind::Union, name, members),
|
||||
}
|
||||
}
|
||||
}
|
||||
117
third-party/vendor/objc2-encode/src/lib.rs
vendored
Normal file
117
third-party/vendor/objc2-encode/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
//! # Objective-C type-encoding
|
||||
//!
|
||||
//! This is re-exported into the top level of `objc2`.
|
||||
//!
|
||||
//! The Objective-C directive `@encode` encodes types as strings, and this is
|
||||
//! used in various places in the runtime.
|
||||
//!
|
||||
//! This crate provides the [`Encoding`] type to efficiently describe and
|
||||
//! compare these type-encodings.
|
||||
//!
|
||||
//! Additionally it provides traits for annotating types that has an
|
||||
//! Objective-C encoding: Specifically [`Encode`] for structs, [`RefEncode`]
|
||||
//! for references and [`EncodeArguments`] for function arguments.
|
||||
//!
|
||||
//! This crate is exported under the [`objc2`] crate as `objc2::encode`, so
|
||||
//! usually you would just use it from there.
|
||||
//!
|
||||
//! [`objc2`]: https://crates.io/crates/objc2
|
||||
//!
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! Implementing [`Encode`] and [`RefEncode`] for a custom type:
|
||||
//!
|
||||
//! ```
|
||||
//! use objc2_encode::{Encode, Encoding, RefEncode};
|
||||
//! // or from objc2:
|
||||
//! // use objc2::{Encode, Encoding, RefEncode};
|
||||
//!
|
||||
//! #[repr(C)]
|
||||
//! struct MyStruct {
|
||||
//! a: f32, // float
|
||||
//! b: i16, // int16_t
|
||||
//! }
|
||||
//!
|
||||
//! unsafe impl Encode for MyStruct {
|
||||
//! const ENCODING: Encoding = Encoding::Struct(
|
||||
//! "MyStruct", // Must use the same name as defined in C header files
|
||||
//! &[
|
||||
//! f32::ENCODING, // Same as Encoding::Float
|
||||
//! i16::ENCODING, // Same as Encoding::Short
|
||||
//! ],
|
||||
//! );
|
||||
//! }
|
||||
//!
|
||||
//! // @encode(MyStruct) -> "{MyStruct=fs}"
|
||||
//! assert!(MyStruct::ENCODING.equivalent_to_str("{MyStruct=fs}"));
|
||||
//!
|
||||
//! unsafe impl RefEncode for MyStruct {
|
||||
//! // Note that if `MyStruct` is an Objective-C instance, this should
|
||||
//! // be `Encoding::Object`.
|
||||
//! const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
|
||||
//! }
|
||||
//!
|
||||
//! // @encode(MyStruct*) -> "^{MyStruct=fs}"
|
||||
//! assert!(MyStruct::ENCODING_REF.equivalent_to_str("^{MyStruct=fs}"));
|
||||
//! ```
|
||||
//!
|
||||
//! See the [`examples`] folder for more complex usage.
|
||||
//!
|
||||
//! [`examples`]: https://github.com/madsmtm/objc2/tree/master/objc2-encode/examples
|
||||
//!
|
||||
//!
|
||||
//! ## Caveats
|
||||
//!
|
||||
//! We've taken the pragmatic approach with [`Encode`] and [`RefEncode`], and
|
||||
//! have implemented it for as many types as possible (instead of defining a
|
||||
//! bunch of subtraits for very specific purposes). However, that might
|
||||
//! sometimes be slightly surprising.
|
||||
//!
|
||||
//! The primary example is [`()`][`unit`], which doesn't make sense as a
|
||||
//! method argument, but is a very common return type, and hence implements
|
||||
//! [`Encode`].
|
||||
//!
|
||||
//!
|
||||
//! ## Further resources
|
||||
//!
|
||||
//! - [Objective-C, Encoding and You](https://dmaclach.medium.com/objective-c-encoding-and-you-866624cc02de).
|
||||
//! - [Apple's documentation on Type Encodings](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html).
|
||||
//! - [How are the digits in ObjC method type encoding calculated?](https://stackoverflow.com/a/11527925)
|
||||
//! - [`clang`'s source code for generating `@encode`](https://github.com/llvm/llvm-project/blob/fae0dfa6421ea6c02f86ba7292fa782e1e2b69d1/clang/lib/AST/ASTContext.cpp#L7500-L7850).
|
||||
|
||||
#![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/objc2-encode/2.0.0-pre.2")]
|
||||
#![cfg_attr(feature = "unstable-c-unwind", feature(c_unwind))]
|
||||
|
||||
#[cfg(doctest)]
|
||||
#[doc = include_str!("../README.md")]
|
||||
extern "C" {}
|
||||
|
||||
#[cfg(any(feature = "std", doc))]
|
||||
extern crate std;
|
||||
|
||||
#[cfg(any(feature = "alloc", test, doc))]
|
||||
extern crate alloc;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod __bool;
|
||||
mod encode;
|
||||
mod encoding;
|
||||
mod helper;
|
||||
mod parse;
|
||||
|
||||
// Will be used at some point when generic constants are available
|
||||
#[allow(dead_code)]
|
||||
mod static_str;
|
||||
|
||||
pub use self::encode::{Encode, EncodeArguments, EncodeConvert, RefEncode};
|
||||
pub use self::encoding::Encoding;
|
||||
67
third-party/vendor/objc2-encode/src/parse.rs
vendored
Normal file
67
third-party/vendor/objc2-encode/src/parse.rs
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
//! Parsing encodings from their string representation.
|
||||
#![deny(unsafe_code)]
|
||||
|
||||
use crate::helper::{Helper, NestingLevel};
|
||||
use crate::Encoding;
|
||||
|
||||
pub(crate) const QUALIFIERS: &[char] = &[
|
||||
'r', // const
|
||||
'n', // in
|
||||
'N', // inout
|
||||
'o', // out
|
||||
'O', // bycopy
|
||||
'R', // byref
|
||||
'V', // oneway
|
||||
];
|
||||
|
||||
pub(crate) fn rm_enc_prefix<'a>(
|
||||
s: &'a str,
|
||||
enc: &Encoding,
|
||||
level: NestingLevel,
|
||||
) -> Option<&'a str> {
|
||||
use Helper::*;
|
||||
match Helper::new(enc) {
|
||||
Primitive(primitive) => s.strip_prefix(primitive.to_str()),
|
||||
BitField(b, _type) => {
|
||||
// TODO: Use the type on GNUStep (nesting level?)
|
||||
let s = s.strip_prefix('b')?;
|
||||
rm_int_prefix(s, b as usize)
|
||||
}
|
||||
Indirection(kind, t) => {
|
||||
let s = s.strip_prefix(kind.prefix())?;
|
||||
rm_enc_prefix(s, t, level.indirection(kind))
|
||||
}
|
||||
Array(len, item) => {
|
||||
let mut s = s;
|
||||
s = s.strip_prefix('[')?;
|
||||
s = rm_int_prefix(s, len)?;
|
||||
s = rm_enc_prefix(s, item, level.array())?;
|
||||
s.strip_prefix(']')
|
||||
}
|
||||
Container(kind, name, fields) => {
|
||||
let mut s = s;
|
||||
s = s.strip_prefix(kind.start())?;
|
||||
s = s.strip_prefix(name)?;
|
||||
if let Some(level) = level.container() {
|
||||
s = s.strip_prefix('=')?;
|
||||
for field in fields {
|
||||
s = rm_enc_prefix(s, field, level)?;
|
||||
}
|
||||
}
|
||||
s.strip_prefix(kind.end())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn chomp_int(s: &str) -> Option<(usize, &str)> {
|
||||
// Chomp until we hit a non-digit
|
||||
let (num, t) = match s.find(|c: char| !c.is_ascii_digit()) {
|
||||
Some(i) => s.split_at(i),
|
||||
None => (s, ""),
|
||||
};
|
||||
num.parse().map(|n| (n, t)).ok()
|
||||
}
|
||||
|
||||
fn rm_int_prefix(s: &str, other: usize) -> Option<&str> {
|
||||
chomp_int(s).and_then(|(n, t)| if other == n { Some(t) } else { None })
|
||||
}
|
||||
208
third-party/vendor/objc2-encode/src/static_str.rs
vendored
Normal file
208
third-party/vendor/objc2-encode/src/static_str.rs
vendored
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
use crate::helper::{Helper, NestingLevel};
|
||||
|
||||
use super::Encoding;
|
||||
|
||||
pub(crate) const fn static_int_str_len(mut n: u128) -> usize {
|
||||
let mut i = 0;
|
||||
if n == 0 {
|
||||
return 1;
|
||||
}
|
||||
while n > 0 {
|
||||
n /= 10;
|
||||
i += 1;
|
||||
}
|
||||
i
|
||||
}
|
||||
|
||||
pub(crate) const fn static_int_str_array<const RES: usize>(mut n: u128) -> [u8; RES] {
|
||||
let mut res: [u8; RES] = [0; RES];
|
||||
let mut i = 0;
|
||||
if n == 0 {
|
||||
res[0] = b'0';
|
||||
return res;
|
||||
}
|
||||
while n > 0 {
|
||||
res[i] = b'0' + (n % 10) as u8;
|
||||
n /= 10;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let mut rev: [u8; RES] = [0; RES];
|
||||
let mut rev_i = 0;
|
||||
while 0 < i {
|
||||
i -= 1;
|
||||
rev[rev_i] = res[i];
|
||||
n /= 10;
|
||||
rev_i += 1;
|
||||
}
|
||||
rev
|
||||
}
|
||||
|
||||
pub(crate) const fn static_encoding_str_len(encoding: &Encoding, level: NestingLevel) -> usize {
|
||||
use Helper::*;
|
||||
|
||||
match Helper::new(encoding) {
|
||||
Primitive(primitive) => primitive.to_str().len(),
|
||||
BitField(b, _type) => {
|
||||
// TODO: Use the type on GNUStep (nesting level?)
|
||||
1 + static_int_str_len(b as u128)
|
||||
}
|
||||
Indirection(kind, t) => 1 + static_encoding_str_len(t, level.indirection(kind)),
|
||||
Array(len, item) => {
|
||||
1 + static_int_str_len(len as u128) + static_encoding_str_len(item, level.array()) + 1
|
||||
}
|
||||
Container(_, name, items) => {
|
||||
let mut res = 1 + name.len();
|
||||
if let Some(level) = level.container() {
|
||||
res += 1;
|
||||
let mut i = 0;
|
||||
while i < items.len() {
|
||||
res += static_encoding_str_len(&items[i], level);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
res + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn static_encoding_str_array<const LEN: usize>(
|
||||
encoding: &Encoding,
|
||||
level: NestingLevel,
|
||||
) -> [u8; LEN] {
|
||||
use Helper::*;
|
||||
|
||||
let mut res: [u8; LEN] = [0; LEN];
|
||||
let mut res_i = 0;
|
||||
|
||||
match Helper::new(encoding) {
|
||||
Primitive(primitive) => {
|
||||
let s = primitive.to_str().as_bytes();
|
||||
let mut i = 0;
|
||||
while i < s.len() {
|
||||
res[i] = s[i];
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
BitField(b, _type) => {
|
||||
// TODO: Use the type on GNUStep (nesting level?)
|
||||
res[res_i] = b'b';
|
||||
res_i += 1;
|
||||
|
||||
let mut i = 0;
|
||||
// We use 3 even though it creates an oversized array
|
||||
let arr = static_int_str_array::<3>(b as u128);
|
||||
while i < static_int_str_len(b as u128) {
|
||||
res[res_i] = arr[i];
|
||||
res_i += 1;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
Indirection(kind, t) => {
|
||||
res[res_i] = kind.prefix_byte();
|
||||
res_i += 1;
|
||||
|
||||
let mut i = 0;
|
||||
// We use LEN even though it creates an oversized array
|
||||
let arr = static_encoding_str_array::<LEN>(t, level.indirection(kind));
|
||||
while i < static_encoding_str_len(t, level.indirection(kind)) {
|
||||
res[res_i] = arr[i];
|
||||
res_i += 1;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
Array(len, item) => {
|
||||
let mut res_i = 0;
|
||||
|
||||
res[res_i] = b'[';
|
||||
res_i += 1;
|
||||
|
||||
let mut i = 0;
|
||||
// We use 20 even though it creates an oversized array
|
||||
let arr = static_int_str_array::<20>(len as u128);
|
||||
while i < static_int_str_len(len as u128) {
|
||||
res[res_i] = arr[i];
|
||||
res_i += 1;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
// We use LEN even though it creates an oversized array
|
||||
let arr = static_encoding_str_array::<LEN>(item, level.array());
|
||||
while i < static_encoding_str_len(item, level.array()) {
|
||||
res[res_i] = arr[i];
|
||||
res_i += 1;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
res[res_i] = b']';
|
||||
}
|
||||
Container(kind, name, items) => {
|
||||
let mut res_i = 0;
|
||||
|
||||
res[res_i] = kind.start_byte();
|
||||
res_i += 1;
|
||||
|
||||
let mut name_i = 0;
|
||||
let name = name.as_bytes();
|
||||
while name_i < name.len() {
|
||||
res[res_i] = name[name_i];
|
||||
res_i += 1;
|
||||
name_i += 1;
|
||||
}
|
||||
|
||||
if let Some(level) = level.container() {
|
||||
res[res_i] = b'=';
|
||||
res_i += 1;
|
||||
|
||||
let mut items_i = 0;
|
||||
while items_i < items.len() {
|
||||
// We use LEN even though it creates an oversized array
|
||||
let field_res = static_encoding_str_array::<LEN>(&items[items_i], level);
|
||||
|
||||
let mut item_res_i = 0;
|
||||
while item_res_i < static_encoding_str_len(&items[items_i], level) {
|
||||
res[res_i] = field_res[item_res_i];
|
||||
res_i += 1;
|
||||
item_res_i += 1;
|
||||
}
|
||||
items_i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
res[res_i] = kind.end_byte();
|
||||
}
|
||||
};
|
||||
res
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
macro_rules! const_int_str {
|
||||
($n:expr) => {{
|
||||
const X: [u8; static_int_str_len($n as u128)] = static_int_str_array($n as u128);
|
||||
unsafe { core::str::from_utf8_unchecked(&X) }
|
||||
}};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_const_int_str() {
|
||||
const STR_0: &str = const_int_str!(0);
|
||||
const STR_4: &str = const_int_str!(4);
|
||||
const STR_42: &str = const_int_str!(42);
|
||||
const STR_100: &str = const_int_str!(100);
|
||||
const STR_999: &str = const_int_str!(999);
|
||||
const STR_1236018655: &str = const_int_str!(1236018655);
|
||||
|
||||
assert_eq!(STR_0, "0");
|
||||
assert_eq!(STR_4, "4");
|
||||
assert_eq!(STR_42, "42");
|
||||
assert_eq!(STR_100, "100");
|
||||
assert_eq!(STR_999, "999");
|
||||
assert_eq!(STR_1236018655, "1236018655");
|
||||
}
|
||||
|
||||
// static encoding tests are in `encoding.rs`
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue