Library changes for Apple WatchOS

This commit is contained in:
Vladimir Michael Eatwell
2022-03-23 16:05:01 +00:00
parent c3605f8c80
commit 439d64a83c
20 changed files with 75 additions and 29 deletions

View File

@@ -131,7 +131,7 @@ const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11
// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "netbsd")))] { if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "watchos"), not(target_os = "netbsd")))] {
// ARM EHABI personality routine. // ARM EHABI personality routine.
// https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf // https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
// //

View File

@@ -15,6 +15,7 @@ fn main() {
|| target.contains("illumos") || target.contains("illumos")
|| target.contains("apple-darwin") || target.contains("apple-darwin")
|| target.contains("apple-ios") || target.contains("apple-ios")
|| target.contains("apple-watchos")
|| target.contains("uwp") || target.contains("uwp")
|| target.contains("windows") || target.contains("windows")
|| target.contains("fuchsia") || target.contains("fuchsia")

View File

@@ -141,7 +141,6 @@ pub mod openbsd;
pub mod redox; pub mod redox;
#[cfg(target_os = "solaris")] #[cfg(target_os = "solaris")]
pub mod solaris; pub mod solaris;
#[cfg(target_os = "solid_asp3")] #[cfg(target_os = "solid_asp3")]
pub mod solid; pub mod solid;
#[cfg(target_os = "vxworks")] #[cfg(target_os = "vxworks")]

View File

@@ -90,6 +90,7 @@ pub mod thread;
target_os = "dragonfly", target_os = "dragonfly",
target_os = "freebsd", target_os = "freebsd",
target_os = "ios", target_os = "ios",
target_os = "watchos",
target_os = "macos", target_os = "macos",
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd" target_os = "openbsd"

View File

@@ -12,6 +12,7 @@ use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, Owned
target_os = "freebsd", target_os = "freebsd",
target_os = "ios", target_os = "ios",
target_os = "macos", target_os = "macos",
target_os = "watchos",
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd" target_os = "openbsd"
))] ))]
@@ -30,6 +31,7 @@ use crate::time::Duration;
target_os = "freebsd", target_os = "freebsd",
target_os = "ios", target_os = "ios",
target_os = "macos", target_os = "macos",
target_os = "watchos",
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd" target_os = "openbsd"
))] ))]
@@ -238,6 +240,7 @@ impl UnixStream {
target_os = "freebsd", target_os = "freebsd",
target_os = "ios", target_os = "ios",
target_os = "macos", target_os = "macos",
target_os = "watchos",
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd" target_os = "openbsd"
))] ))]

View File

@@ -36,7 +36,7 @@ pub use self::impl_linux::peer_cred;
))] ))]
pub use self::impl_bsd::peer_cred; pub use self::impl_bsd::peer_cred;
#[cfg(any(target_os = "macos", target_os = "ios",))] #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
pub use self::impl_mac::peer_cred; pub use self::impl_mac::peer_cred;
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "android"))]
@@ -97,7 +97,7 @@ pub mod impl_bsd {
} }
} }
#[cfg(any(target_os = "macos", target_os = "ios",))] #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
pub mod impl_mac { pub mod impl_mac {
use super::UCred; use super::UCred;
use crate::os::unix::io::AsRawFd; use crate::os::unix::io::AsRawFd;

View File

@@ -9,6 +9,7 @@ use libc::{getegid, geteuid, getpid};
target_os = "freebsd", target_os = "freebsd",
target_os = "ios", target_os = "ios",
target_os = "macos", target_os = "macos",
target_os = "watchos",
target_os = "openbsd" target_os = "openbsd"
))] ))]
fn test_socket_pair() { fn test_socket_pair() {
@@ -25,7 +26,7 @@ fn test_socket_pair() {
} }
#[test] #[test]
#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos",))] #[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos", target_os = "watchos"))]
fn test_socket_pair_pids(arg: Type) -> RetType { fn test_socket_pair_pids(arg: Type) -> RetType {
// Create two connected sockets and get their peer credentials. // Create two connected sockets and get their peer credentials.
let (sock_a, sock_b) = UnixStream::pair().unwrap(); let (sock_a, sock_b) = UnixStream::pair().unwrap();

View File

@@ -151,7 +151,7 @@ mod imp {
} }
} }
#[cfg(any(target_os = "macos", target_os = "ios"))] #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
mod imp { mod imp {
use super::Args; use super::Args;
use crate::ffi::CStr; use crate::ffi::CStr;
@@ -192,7 +192,7 @@ mod imp {
// for i in (0..[args count]) // for i in (0..[args count])
// res.push([args objectAtIndex:i]) // res.push([args objectAtIndex:i])
// res // res
#[cfg(target_os = "ios")] #[cfg(any(target_os = "ios", target_os = "watchos"))]
pub fn args() -> Args { pub fn args() -> Args {
use crate::ffi::OsString; use crate::ffi::OsString;
use crate::mem; use crate::mem;

View File

@@ -31,6 +31,17 @@ pub mod os {
pub const EXE_EXTENSION: &str = ""; pub const EXE_EXTENSION: &str = "";
} }
#[cfg(target_os = "watchos")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "watchos";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".dylib";
pub const DLL_EXTENSION: &str = "dylib";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "freebsd")] #[cfg(target_os = "freebsd")]
pub mod os { pub mod os {
pub const FAMILY: &str = "unix"; pub const FAMILY: &str = "unix";

View File

@@ -47,6 +47,7 @@ const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
target_os = "macos", target_os = "macos",
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd", target_os = "openbsd",
target_os = "watchos",
))] ))]
const fn max_iov() -> usize { const fn max_iov() -> usize {
libc::IOV_MAX as usize libc::IOV_MAX as usize
@@ -67,7 +68,8 @@ const fn max_iov() -> usize {
target_os = "macos", target_os = "macos",
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd", target_os = "openbsd",
target_os = "horizon" target_os = "horizon",
target_os = "watchos",
)))] )))]
const fn max_iov() -> usize { const fn max_iov() -> usize {
16 // The minimum value required by POSIX. 16 // The minimum value required by POSIX.

View File

@@ -17,6 +17,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
all(target_os = "linux", target_env = "gnu"), all(target_os = "linux", target_env = "gnu"),
target_os = "macos", target_os = "macos",
target_os = "ios", target_os = "ios",
target_os = "watchos",
))] ))]
use crate::sys::weak::syscall; use crate::sys::weak::syscall;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
@@ -27,6 +28,7 @@ use libc::{c_int, mode_t};
#[cfg(any( #[cfg(any(
target_os = "macos", target_os = "macos",
target_os = "ios", target_os = "ios",
target_os = "watchos",
all(target_os = "linux", target_env = "gnu") all(target_os = "linux", target_env = "gnu")
))] ))]
use libc::c_char; use libc::c_char;
@@ -443,7 +445,8 @@ impl FileAttr {
target_os = "freebsd", target_os = "freebsd",
target_os = "openbsd", target_os = "openbsd",
target_os = "macos", target_os = "macos",
target_os = "ios" target_os = "ios",
target_os = "watchos",
))] ))]
pub fn created(&self) -> io::Result<SystemTime> { pub fn created(&self) -> io::Result<SystemTime> {
Ok(SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64)) Ok(SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64))
@@ -453,7 +456,8 @@ impl FileAttr {
target_os = "freebsd", target_os = "freebsd",
target_os = "openbsd", target_os = "openbsd",
target_os = "macos", target_os = "macos",
target_os = "ios" target_os = "ios",
target_os = "watchos",
)))] )))]
pub fn created(&self) -> io::Result<SystemTime> { pub fn created(&self) -> io::Result<SystemTime> {
cfg_has_statx! { cfg_has_statx! {
@@ -707,6 +711,7 @@ impl DirEntry {
#[cfg(any( #[cfg(any(
target_os = "macos", target_os = "macos",
target_os = "ios", target_os = "ios",
target_os = "watchos",
target_os = "linux", target_os = "linux",
target_os = "emscripten", target_os = "emscripten",
target_os = "android", target_os = "android",
@@ -737,6 +742,7 @@ impl DirEntry {
#[cfg(any( #[cfg(any(
target_os = "macos", target_os = "macos",
target_os = "ios", target_os = "ios",
target_os = "watchos",
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd", target_os = "openbsd",
target_os = "freebsd", target_os = "freebsd",
@@ -754,6 +760,7 @@ impl DirEntry {
#[cfg(not(any( #[cfg(not(any(
target_os = "macos", target_os = "macos",
target_os = "ios", target_os = "ios",
target_os = "watchos",
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd", target_os = "openbsd",
target_os = "freebsd", target_os = "freebsd",
@@ -911,11 +918,11 @@ impl File {
cvt_r(|| unsafe { os_fsync(self.as_raw_fd()) })?; cvt_r(|| unsafe { os_fsync(self.as_raw_fd()) })?;
return Ok(()); return Ok(());
#[cfg(any(target_os = "macos", target_os = "ios"))] #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
unsafe fn os_fsync(fd: c_int) -> c_int { unsafe fn os_fsync(fd: c_int) -> c_int {
libc::fcntl(fd, libc::F_FULLFSYNC) libc::fcntl(fd, libc::F_FULLFSYNC)
} }
#[cfg(not(any(target_os = "macos", target_os = "ios")))] #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "watchos")))]
unsafe fn os_fsync(fd: c_int) -> c_int { unsafe fn os_fsync(fd: c_int) -> c_int {
libc::fsync(fd) libc::fsync(fd)
} }
@@ -925,7 +932,7 @@ impl File {
cvt_r(|| unsafe { os_datasync(self.as_raw_fd()) })?; cvt_r(|| unsafe { os_datasync(self.as_raw_fd()) })?;
return Ok(()); return Ok(());
#[cfg(any(target_os = "macos", target_os = "ios"))] #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
unsafe fn os_datasync(fd: c_int) -> c_int { unsafe fn os_datasync(fd: c_int) -> c_int {
libc::fcntl(fd, libc::F_FULLFSYNC) libc::fcntl(fd, libc::F_FULLFSYNC)
} }
@@ -946,7 +953,8 @@ impl File {
target_os = "linux", target_os = "linux",
target_os = "macos", target_os = "macos",
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd" target_os = "openbsd",
target_os = "watchos",
)))] )))]
unsafe fn os_datasync(fd: c_int) -> c_int { unsafe fn os_datasync(fd: c_int) -> c_int {
libc::fsync(fd) libc::fsync(fd)
@@ -1396,7 +1404,8 @@ fn open_to_and_set_permissions(
target_os = "linux", target_os = "linux",
target_os = "android", target_os = "android",
target_os = "macos", target_os = "macos",
target_os = "ios" target_os = "ios",
target_os = "watchos",
)))] )))]
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
let (mut reader, reader_metadata) = open_from(from)?; let (mut reader, reader_metadata) = open_from(from)?;
@@ -1423,7 +1432,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
} }
} }
#[cfg(any(target_os = "macos", target_os = "ios"))] #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::atomic::{AtomicBool, Ordering};

View File

@@ -37,6 +37,7 @@ impl Condvar {
#[cfg(any( #[cfg(any(
target_os = "macos", target_os = "macos",
target_os = "ios", target_os = "ios",
target_os = "watchos",
target_os = "l4re", target_os = "l4re",
target_os = "android", target_os = "android",
target_os = "redox" target_os = "redox"
@@ -58,6 +59,7 @@ impl Condvar {
#[cfg(not(any( #[cfg(not(any(
target_os = "macos", target_os = "macos",
target_os = "ios", target_os = "ios",
target_os = "watchos",
target_os = "l4re", target_os = "l4re",
target_os = "android", target_os = "android",
target_os = "redox", target_os = "redox",
@@ -102,6 +104,7 @@ impl Condvar {
#[cfg(not(any( #[cfg(not(any(
target_os = "macos", target_os = "macos",
target_os = "ios", target_os = "ios",
target_os = "watchos",
target_os = "android", target_os = "android",
target_os = "espidf", target_os = "espidf",
target_os = "horizon" target_os = "horizon"
@@ -135,6 +138,7 @@ impl Condvar {
#[cfg(any( #[cfg(any(
target_os = "macos", target_os = "macos",
target_os = "ios", target_os = "ios",
target_os = "watchos",
target_os = "android", target_os = "android",
target_os = "espidf", target_os = "espidf",
target_os = "horizon" target_os = "horizon"

View File

@@ -86,6 +86,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
// The poll on Darwin doesn't set POLLNVAL for closed fds. // The poll on Darwin doesn't set POLLNVAL for closed fds.
target_os = "macos", target_os = "macos",
target_os = "ios", target_os = "ios",
target_os = "watchos",
target_os = "redox", target_os = "redox",
target_os = "l4re", target_os = "l4re",
target_os = "horizon", target_os = "horizon",
@@ -329,7 +330,7 @@ cfg_if::cfg_if! {
// See #41582 and https://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html // See #41582 and https://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html
#[link(name = "resolv")] #[link(name = "resolv")]
extern "C" {} extern "C" {}
} else if #[cfg(target_os = "ios")] { } else if #[cfg(any(target_os = "ios", target_os = "watchos"))] {
#[link(name = "System")] #[link(name = "System")]
#[link(name = "objc")] #[link(name = "objc")]
#[link(name = "Security", kind = "framework")] #[link(name = "Security", kind = "framework")]

View File

@@ -61,7 +61,7 @@ extern "C" {
)] )]
#[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")] #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")]
#[cfg_attr( #[cfg_attr(
any(target_os = "macos", target_os = "ios", target_os = "freebsd"), any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "watchos"),
link_name = "__error" link_name = "__error"
)] )]
#[cfg_attr(target_os = "haiku", link_name = "_errnop")] #[cfg_attr(target_os = "haiku", link_name = "_errnop")]
@@ -361,7 +361,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
} }
} }
#[cfg(any(target_os = "macos", target_os = "ios"))] #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
pub fn current_exe() -> io::Result<PathBuf> { pub fn current_exe() -> io::Result<PathBuf> {
unsafe { unsafe {
let mut sz: u32 = 0; let mut sz: u32 = 0;
@@ -598,6 +598,7 @@ pub fn home_dir() -> Option<PathBuf> {
#[cfg(any( #[cfg(any(
target_os = "android", target_os = "android",
target_os = "ios", target_os = "ios",
target_os = "watchos",
target_os = "emscripten", target_os = "emscripten",
target_os = "redox", target_os = "redox",
target_os = "vxworks", target_os = "vxworks",
@@ -610,6 +611,7 @@ pub fn home_dir() -> Option<PathBuf> {
#[cfg(not(any( #[cfg(not(any(
target_os = "android", target_os = "android",
target_os = "ios", target_os = "ios",
target_os = "watchos",
target_os = "emscripten", target_os = "emscripten",
target_os = "redox", target_os = "redox",
target_os = "vxworks", target_os = "vxworks",

View File

@@ -14,6 +14,7 @@ pub fn hashmap_random_keys() -> (u64, u64) {
unix, unix,
not(target_os = "macos"), not(target_os = "macos"),
not(target_os = "ios"), not(target_os = "ios"),
not(target_os = "watchos"),
not(target_os = "openbsd"), not(target_os = "openbsd"),
not(target_os = "freebsd"), not(target_os = "freebsd"),
not(target_os = "netbsd"), not(target_os = "netbsd"),
@@ -195,7 +196,7 @@ mod imp {
// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is // once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
// only used on iOS where direct access to `/dev/urandom` is blocked by the // only used on iOS where direct access to `/dev/urandom` is blocked by the
// sandbox. // sandbox.
#[cfg(target_os = "ios")] #[cfg(any(target_os = "ios", target_os = "watchos"))]
mod imp { mod imp {
use crate::io; use crate::io;
use crate::ptr; use crate::ptr;

View File

@@ -139,7 +139,7 @@ impl Thread {
} }
} }
#[cfg(any(target_os = "macos", target_os = "ios"))] #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
pub fn set_name(name: &CStr) { pub fn set_name(name: &CStr) {
unsafe { unsafe {
libc::pthread_setname_np(name.as_ptr()); libc::pthread_setname_np(name.as_ptr());

View File

@@ -51,7 +51,12 @@ unsafe fn wait_timeout(
) { ) {
// Use the system clock on systems that do not support pthread_condattr_setclock. // Use the system clock on systems that do not support pthread_condattr_setclock.
// This unfortunately results in problems when the system time changes. // This unfortunately results in problems when the system time changes.
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "espidf"))] #[cfg(any(
target_os = "macos",
target_os = "ios",
target_os = "watchos",
target_os = "espidf"
))]
let (now, dur) = { let (now, dur) = {
use super::time::SystemTime; use super::time::SystemTime;
use crate::cmp::min; use crate::cmp::min;
@@ -72,7 +77,12 @@ unsafe fn wait_timeout(
(now, dur) (now, dur)
}; };
// Use the monotonic clock on other systems. // Use the monotonic clock on other systems.
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "espidf")))] #[cfg(not(any(
target_os = "macos",
target_os = "ios",
target_os = "watchos",
target_os = "espidf"
)))]
let (now, dur) = { let (now, dur) = {
use super::time::Timespec; use super::time::Timespec;
@@ -110,6 +120,7 @@ impl Parker {
if #[cfg(any( if #[cfg(any(
target_os = "macos", target_os = "macos",
target_os = "ios", target_os = "ios",
target_os = "watchos",
target_os = "l4re", target_os = "l4re",
target_os = "android", target_os = "android",
target_os = "redox" target_os = "redox"

View File

@@ -141,7 +141,7 @@ impl From<libc::timespec> for Timespec {
} }
} }
#[cfg(any(target_os = "macos", target_os = "ios"))] #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
mod inner { mod inner {
use crate::sync::atomic::{AtomicU64, Ordering}; use crate::sync::atomic::{AtomicU64, Ordering};
use crate::sys::cvt; use crate::sys::cvt;
@@ -257,7 +257,7 @@ mod inner {
} }
} }
#[cfg(not(any(target_os = "macos", target_os = "ios")))] #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "watchos")))]
mod inner { mod inner {
use crate::fmt; use crate::fmt;
use crate::mem::MaybeUninit; use crate::mem::MaybeUninit;

View File

@@ -18,7 +18,7 @@ use libc::{c_int, c_void};
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(any( if #[cfg(any(
target_os = "dragonfly", target_os = "freebsd", target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos", target_os = "ios", target_os = "macos", target_os = "watchos",
target_os = "openbsd", target_os = "netbsd", target_os = "illumos", target_os = "openbsd", target_os = "netbsd", target_os = "illumos",
target_os = "solaris", target_os = "haiku", target_os = "l4re"))] { target_os = "solaris", target_os = "haiku", target_os = "l4re"))] {
use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;

View File

@@ -30,10 +30,10 @@ pub const unwinder_private_data_size: usize = 5;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
pub const unwinder_private_data_size: usize = 6; pub const unwinder_private_data_size: usize = 6;
#[cfg(all(target_arch = "arm", not(target_os = "ios")))] #[cfg(all(target_arch = "arm", not(any(target_os = "ios", target_os = "watchos"))))]
pub const unwinder_private_data_size: usize = 20; pub const unwinder_private_data_size: usize = 20;
#[cfg(all(target_arch = "arm", target_os = "ios"))] #[cfg(all(target_arch = "arm", any(target_os = "ios", target_os = "watchos")))]
pub const unwinder_private_data_size: usize = 5; pub const unwinder_private_data_size: usize = 5;
#[cfg(all(target_arch = "aarch64", target_pointer_width = "64"))] #[cfg(all(target_arch = "aarch64", target_pointer_width = "64"))]
@@ -105,7 +105,7 @@ extern "C" {
} }
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm")))] { if #[cfg(any(target_os = "ios", target_os = "watchos", target_os = "netbsd", not(target_arch = "arm")))] {
// Not ARM EHABI // Not ARM EHABI
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq)]