Make bolts work without alloc (#1401)
* Make bolts work without alloc * Use core::Error where available * unstable_feature -> nightly * windows no_alloc
This commit is contained in:
parent
a0c03fccc5
commit
dfaf06a22e
4
.github/workflows/build_and_test.yml
vendored
4
.github/workflows/build_and_test.yml
vendored
@ -49,6 +49,8 @@ jobs:
|
||||
run: cargo test
|
||||
- name: Test libafl no_std
|
||||
run: cd libafl && cargo test --no-default-features
|
||||
- name: Test libafl_bolts no_std no_alloc
|
||||
run: cd libafl_bolts && cargo test --no-default-features
|
||||
- name: Test libafl_targets no_std
|
||||
run: cd libafl_targets && cargo test --no-default-features
|
||||
|
||||
@ -285,6 +287,8 @@ jobs:
|
||||
run: cd ./libafl && cargo test --no-default-features
|
||||
- name: libafl armv6m-none-eabi (32 bit no_std) clippy
|
||||
run: cd ./libafl && cargo clippy --target thumbv6m-none-eabi --no-default-features
|
||||
- name: Build no_std no_alloc bolts
|
||||
run: cd ./libafl_bolts && cargo +nightly build -Zbuild-std=core --target aarch64-unknown-none --no-default-features -v --release && cd ../
|
||||
|
||||
build-docker:
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -61,7 +61,7 @@ serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
|
||||
bytecount = "0.6.3"
|
||||
|
||||
[dependencies]
|
||||
libafl_bolts = { version = "0.10.1", path = "../libafl_bolts", default-features = false }
|
||||
libafl_bolts = { version = "0.10.1", path = "../libafl_bolts", default-features = false, features = ["alloc"] }
|
||||
libafl_derive = { version = "0.10.1", path = "../libafl_derive", optional = true }
|
||||
|
||||
rustversion = "1.0"
|
||||
|
@ -1,7 +1,7 @@
|
||||
#[rustversion::nightly]
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rustc-cfg=unstable_feature");
|
||||
println!("cargo:rustc-cfg=nightly");
|
||||
}
|
||||
|
||||
#[rustversion::not(nightly)]
|
||||
|
@ -5,11 +5,11 @@ Welcome to `LibAFL`
|
||||
#![allow(incomplete_features)]
|
||||
#![no_std]
|
||||
// For `type_eq`
|
||||
#![cfg_attr(unstable_feature, feature(specialization))]
|
||||
#![cfg_attr(nightly, feature(specialization))]
|
||||
// For `type_id` and owned things
|
||||
#![cfg_attr(unstable_feature, feature(intrinsics))]
|
||||
#![cfg_attr(nightly, feature(intrinsics))]
|
||||
// For `std::simd`
|
||||
#![cfg_attr(unstable_feature, feature(portable_simd))]
|
||||
#![cfg_attr(nightly, feature(portable_simd))]
|
||||
#![warn(clippy::cargo)]
|
||||
#![allow(ambiguous_glob_reexports)]
|
||||
#![deny(clippy::cargo_common_metadata)]
|
||||
|
@ -21,9 +21,9 @@ pub mod concolic;
|
||||
pub mod value;
|
||||
|
||||
// Rust is breaking this with 'error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `type_id`' and so we disable this component for the moment
|
||||
//#[cfg(unstable_feature)]
|
||||
//#[cfg(nightly)]
|
||||
//pub mod owned;
|
||||
//#[cfg(unstable_feature)]
|
||||
//#[cfg(nightly)]
|
||||
//pub use owned::*;
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
|
@ -12,14 +12,15 @@ edition = "2021"
|
||||
categories = ["development-tools::testing", "emulators", "embedded", "os", "no-std"]
|
||||
|
||||
[features]
|
||||
default = ["std", "derive", "llmp_compression", "llmp_small_maps", "rand_trait", "prelude", "gzip", "serdeany_autoreg"]
|
||||
std = ["serde_json", "serde_json/std", "hostname", "nix", "serde/std", "once_cell", "uuid", "byteorder", "backtrace", "uds", "serial_test"] # print, env, launcher ... support
|
||||
default = ["std", "derive", "llmp_compression", "llmp_small_maps", "rand_trait", "prelude", "gzip", "serdeany_autoreg", "alloc"]
|
||||
std = ["serde_json", "serde_json/std", "hostname", "nix", "serde/std", "once_cell", "uuid", "byteorder", "backtrace", "uds", "serial_test", "alloc"] # print, env, ... support
|
||||
alloc = ["serde/alloc", "hashbrown", "postcard", "erased-serde/alloc", "ahash"] # Enables all features that allocate in no_std
|
||||
derive = ["libafl_derive"] # provide derive(SerdeAny) macro.
|
||||
rand_trait = ["rand_core"] # If set, libafl's rand implementations will implement `rand::Rng`
|
||||
python = ["pyo3"]
|
||||
python = ["pyo3", "std"]
|
||||
prelude = [] # Expose libafl::prelude for access without additional using directives
|
||||
cli = ["clap"] # expose libafl_bolts::cli for easy commandline parsing
|
||||
qemu_cli = ["cli"] # Commandline flags for qemu-based fuzzers
|
||||
qemu_cli = ["cli"] # Commandline flagr for qemu-based fuzzers
|
||||
frida_cli = ["cli"] # Commandline flags for frida-based fuzzers
|
||||
errors_backtrace = ["backtrace"]
|
||||
gzip = ["miniz_oxide"] # Enables gzip compression in certain parts of the lib
|
||||
@ -28,10 +29,10 @@ gzip = ["miniz_oxide"] # Enables gzip compression in certain parts of the lib
|
||||
serdeany_autoreg = ["ctor"] # Automatically register all `#[derive(SerdeAny)]` types at startup.
|
||||
|
||||
# LLMP features
|
||||
llmp_bind_public = [] # If set, llmp will bind to 0.0.0.0, allowing cross-device communication. Binds to localhost by default.
|
||||
llmp_compression = ["gzip"] # llmp compression using GZip
|
||||
llmp_debug = [] # Enables debug output for LLMP
|
||||
llmp_small_maps = [] # reduces initial map size for llmp
|
||||
llmp_bind_public = ["alloc"] # If set, llmp will bind to 0.0.0.0, allowing cross-device communication. Binds to localhost by default.
|
||||
llmp_compression = ["alloc", "gzip"] # llmp compression using GZip
|
||||
llmp_debug = ["alloc"] # Enables debug output for LLMP
|
||||
llmp_small_maps = ["alloc"] # reduces initial map size for llmp
|
||||
|
||||
[build-dependencies]
|
||||
rustversion = "1.0"
|
||||
@ -45,13 +46,13 @@ libafl_derive = { version = "0.10.1", optional = true, path = "../libafl_derive"
|
||||
|
||||
rustversion = "1.0"
|
||||
tuple_list = { version = "0.1.3" }
|
||||
hashbrown = { version = "0.14", features = ["serde", "ahash"], default-features=false } # A faster hashmap, nostd compatible
|
||||
hashbrown = { version = "0.14", features = ["serde", "ahash"], default-features=false, optional = true } # A faster hashmap, nostd compatible
|
||||
xxhash-rust = { version = "0.8.5", features = ["xxh3"] } # xxh3 hashing for rust
|
||||
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } # serialization lib
|
||||
erased-serde = { version = "0.3.21", default-features = false, features = ["alloc"] } # erased serde
|
||||
postcard = { version = "1.0", features = ["alloc"] } # no_std compatible serde serialization format
|
||||
serde = { version = "1.0", default-features = false, features = ["derive"] } # serialization lib
|
||||
erased-serde = { version = "0.3.21", default-features = false, optional = true } # erased serde
|
||||
postcard = { version = "1.0", features = ["alloc"], optional = true } # no_std compatible serde serialization format
|
||||
num_enum = { version = "0.5.7", default-features = false }
|
||||
ahash = { version = "0.8", default-features=false } # The hash function already used in hashbrown
|
||||
ahash = { version = "0.8", default-features=false, optional = true } # The hash function already used in hashbrown
|
||||
backtrace = {version = "0.3", optional = true} # Used to get the stacktrace in StacktraceObserver
|
||||
|
||||
ctor = { optional = true, version = "0.2" }
|
||||
|
@ -1,7 +1,7 @@
|
||||
#[rustversion::nightly]
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rustc-cfg=unstable_feature");
|
||||
println!("cargo:rustc-cfg=nightly");
|
||||
}
|
||||
|
||||
#[rustversion::not(nightly)]
|
||||
|
@ -7,11 +7,13 @@ Welcome to `LibAFL`
|
||||
#![allow(incomplete_features)]
|
||||
#![no_std]
|
||||
// For `type_eq`
|
||||
#![cfg_attr(unstable_feature, feature(specialization))]
|
||||
#![cfg_attr(nightly, feature(specialization))]
|
||||
// For `type_id` and owned things
|
||||
#![cfg_attr(unstable_feature, feature(intrinsics))]
|
||||
#![cfg_attr(nightly, feature(intrinsics))]
|
||||
// For `std::simd`
|
||||
#![cfg_attr(unstable_feature, feature(portable_simd))]
|
||||
#![cfg_attr(nightly, feature(portable_simd))]
|
||||
// For `core::error`
|
||||
#![cfg_attr(nightly, feature(error_in_core))]
|
||||
#![warn(clippy::cargo)]
|
||||
#![allow(ambiguous_glob_reexports)]
|
||||
#![deny(clippy::cargo_common_metadata)]
|
||||
@ -78,6 +80,7 @@ Welcome to `LibAFL`
|
||||
#[cfg(feature = "std")]
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
#[cfg(feature = "alloc")]
|
||||
#[macro_use]
|
||||
#[doc(hidden)]
|
||||
pub extern crate alloc;
|
||||
@ -98,10 +101,11 @@ pub mod launcher {}
|
||||
#[allow(unused_imports)]
|
||||
#[macro_use]
|
||||
extern crate libafl_derive;
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::string::{FromUtf8Error, String};
|
||||
use core::{
|
||||
array::TryFromSliceError,
|
||||
fmt,
|
||||
fmt::{self, Display},
|
||||
num::{ParseIntError, TryFromIntError},
|
||||
};
|
||||
#[cfg(feature = "std")]
|
||||
@ -110,6 +114,21 @@ use std::{env::VarError, io};
|
||||
#[cfg(feature = "libafl_derive")]
|
||||
pub use libafl_derive::SerdeAny;
|
||||
|
||||
/// We need some sort of "[`String`]" for errors in `no_alloc`...
|
||||
/// We can only support `'static` without allocator, so let's do that.
|
||||
#[cfg(not(feature = "alloc"))]
|
||||
type String = &'static str;
|
||||
|
||||
/// We also need a non-allocating format...
|
||||
/// This one simply returns the `fmt` string.
|
||||
/// Good enough for simple errors, for anything else, use the `alloc` feature.
|
||||
#[cfg(not(feature = "alloc"))]
|
||||
macro_rules! format {
|
||||
($fmt:literal) => {{
|
||||
$fmt
|
||||
}};
|
||||
}
|
||||
|
||||
/// We need fixed names for many parts of this lib.
|
||||
pub trait Named {
|
||||
/// Provide the name of this element.
|
||||
@ -276,7 +295,7 @@ impl Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Serialize(s, b) => {
|
||||
@ -339,6 +358,7 @@ impl fmt::Display for Error {
|
||||
}
|
||||
|
||||
/// Stringify the postcard serializer error
|
||||
#[cfg(feature = "alloc")]
|
||||
impl From<postcard::Error> for Error {
|
||||
fn from(err: postcard::Error) -> Self {
|
||||
Self::serialize(format!("{err:?}"))
|
||||
@ -368,7 +388,9 @@ impl From<io::Error> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl From<FromUtf8Error> for Error {
|
||||
#[allow(unused_variables)]
|
||||
fn from(err: FromUtf8Error) -> Self {
|
||||
Self::unknown(format!("Could not convert byte / utf-8: {err:?}"))
|
||||
}
|
||||
@ -376,24 +398,28 @@ impl From<FromUtf8Error> for Error {
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<VarError> for Error {
|
||||
#[allow(unused_variables)]
|
||||
fn from(err: VarError) -> Self {
|
||||
Self::empty(format!("Could not get env var: {err:?}"))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParseIntError> for Error {
|
||||
#[allow(unused_variables)]
|
||||
fn from(err: ParseIntError) -> Self {
|
||||
Self::unknown(format!("Failed to parse Int: {err:?}"))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TryFromIntError> for Error {
|
||||
#[allow(unused_variables)]
|
||||
fn from(err: TryFromIntError) -> Self {
|
||||
Self::illegal_state(format!("Expected conversion failed: {err:?}"))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TryFromSliceError> for Error {
|
||||
#[allow(unused_variables)]
|
||||
fn from(err: TryFromSliceError) -> Self {
|
||||
Self::illegal_argument(format!("Could not convert slice: {err:?}"))
|
||||
}
|
||||
@ -401,6 +427,7 @@ impl From<TryFromSliceError> for Error {
|
||||
|
||||
#[cfg(windows)]
|
||||
impl From<windows::core::Error> for Error {
|
||||
#[allow(unused_variables)]
|
||||
fn from(err: windows::core::Error) -> Self {
|
||||
Self::unknown(format!("Windows API error: {err:?}"))
|
||||
}
|
||||
@ -422,9 +449,12 @@ impl From<pyo3::PyErr> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(all(not(nightly), feature = "std"))]
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
#[cfg(nightly)]
|
||||
impl core::error::Error for Error {}
|
||||
|
||||
/// The purpose of this module is to alleviate imports of many components by adding a glob import.
|
||||
#[cfg(feature = "prelude")]
|
||||
pub mod prelude {
|
||||
@ -439,6 +469,7 @@ pub unsafe extern "C" fn external_current_millis() -> u64 {
|
||||
1000
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod anymap;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod build_id;
|
||||
@ -454,18 +485,22 @@ pub mod core_affinity;
|
||||
pub mod cpu;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod fs;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod llmp;
|
||||
#[cfg(all(feature = "std", unix))]
|
||||
pub mod minibsod;
|
||||
pub mod os;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod ownedref;
|
||||
pub mod rands;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod serdeany;
|
||||
pub mod shmem;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod staterestore;
|
||||
pub mod tuples;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::vec::Vec;
|
||||
use core::{iter::Iterator, ops::AddAssign, time};
|
||||
#[cfg(feature = "std")]
|
||||
@ -499,6 +534,7 @@ pub trait AsMutSlice {
|
||||
fn as_mut_slice(&mut self) -> &mut [Self::Entry];
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<T> AsSlice for Vec<T> {
|
||||
type Entry = T;
|
||||
|
||||
@ -507,6 +543,7 @@ impl<T> AsSlice for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<T> AsMutSlice for Vec<T> {
|
||||
type Entry = T;
|
||||
|
||||
@ -653,6 +690,7 @@ pub fn current_milliseconds() -> u64 {
|
||||
}
|
||||
|
||||
/// Format a `Duration` into a HMS string
|
||||
#[cfg(feature = "alloc")]
|
||||
#[must_use]
|
||||
pub fn format_duration_hms(duration: &time::Duration) -> String {
|
||||
let secs = duration.as_secs();
|
||||
@ -802,9 +840,9 @@ pub mod bolts_prelude {
|
||||
pub use super::minibsod::*;
|
||||
#[cfg(feature = "std")]
|
||||
pub use super::staterestore::*;
|
||||
pub use super::{
|
||||
anymap::*, cpu::*, llmp::*, os::*, ownedref::*, rands::*, serdeany::*, shmem::*, tuples::*,
|
||||
};
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use super::{anymap::*, llmp::*, ownedref::*, rands::*, serdeany::*, shmem::*, tuples::*};
|
||||
pub use super::{cpu::*, os::*, rands::*};
|
||||
}
|
||||
|
||||
#[cfg(feature = "python")]
|
||||
|
@ -1,12 +1,16 @@
|
||||
//! Signal handling for unix
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::vec::Vec;
|
||||
#[cfg(feature = "alloc")]
|
||||
use core::{
|
||||
cell::UnsafeCell,
|
||||
fmt::{self, Display, Formatter},
|
||||
mem, ptr,
|
||||
ptr::{addr_of_mut, write_volatile},
|
||||
ptr::{self, addr_of_mut, write_volatile},
|
||||
sync::atomic::{compiler_fence, Ordering},
|
||||
};
|
||||
use core::{
|
||||
fmt::{self, Display, Formatter},
|
||||
mem,
|
||||
};
|
||||
#[cfg(feature = "std")]
|
||||
use std::ffi::CString;
|
||||
|
||||
@ -241,11 +245,15 @@ use libc::ssize_t;
|
||||
)))]
|
||||
pub use libc::ucontext_t;
|
||||
use libc::{
|
||||
c_int, malloc, sigaction, sigaddset, sigaltstack, sigemptyset, stack_t, SA_NODEFER, SA_ONSTACK,
|
||||
SA_SIGINFO, SIGABRT, SIGALRM, SIGBUS, SIGFPE, SIGHUP, SIGILL, SIGINT, SIGKILL, SIGPIPE,
|
||||
SIGQUIT, SIGSEGV, SIGTERM, SIGTRAP, SIGUSR2,
|
||||
c_int, SIGABRT, SIGALRM, SIGBUS, SIGFPE, SIGHUP, SIGILL, SIGINT, SIGKILL, SIGPIPE, SIGQUIT,
|
||||
SIGSEGV, SIGTERM, SIGTRAP, SIGUSR2,
|
||||
};
|
||||
pub use libc::{c_void, siginfo_t};
|
||||
#[cfg(feature = "alloc")]
|
||||
use libc::{
|
||||
malloc, sigaction, sigaddset, sigaltstack, sigemptyset, stack_t, SA_NODEFER, SA_ONSTACK,
|
||||
SA_SIGINFO,
|
||||
};
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
|
||||
use crate::Error;
|
||||
@ -335,6 +343,7 @@ impl Display for Signal {
|
||||
}
|
||||
|
||||
/// A trait for `LibAFL` signal handling
|
||||
#[cfg(feature = "alloc")]
|
||||
pub trait Handler {
|
||||
/// Handle a signal
|
||||
fn handle(&mut self, signal: Signal, info: siginfo_t, _context: &mut ucontext_t);
|
||||
@ -342,18 +351,24 @@ pub trait Handler {
|
||||
fn signals(&self) -> Vec<Signal>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
struct HandlerHolder {
|
||||
handler: UnsafeCell<*mut dyn Handler>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
unsafe impl Send for HandlerHolder {}
|
||||
|
||||
/// Let's get 8 mb for now.
|
||||
#[cfg(feature = "alloc")]
|
||||
const SIGNAL_STACK_SIZE: usize = 2 << 22;
|
||||
|
||||
/// To be able to handle SIGSEGV when the stack is exhausted, we need our own little stack space.
|
||||
#[cfg(feature = "alloc")]
|
||||
static mut SIGNAL_STACK_PTR: *mut c_void = ptr::null_mut();
|
||||
|
||||
/// Keep track of which handler is registered for which signal
|
||||
#[cfg(feature = "alloc")]
|
||||
static mut SIGNAL_HANDLERS: [Option<HandlerHolder>; 32] = [
|
||||
// We cannot use [None; 32] because it requires Copy. Ugly, but I don't think there's an
|
||||
// alternative.
|
||||
@ -362,9 +377,11 @@ static mut SIGNAL_HANDLERS: [Option<HandlerHolder>; 32] = [
|
||||
];
|
||||
|
||||
/// Internal function that is being called whenever a signal we are registered for arrives.
|
||||
///
|
||||
/// # Safety
|
||||
/// This should be somewhat safe to call for signals previously registered,
|
||||
/// unless the signal handlers registered using [`setup_signal_handler()`] are broken.
|
||||
#[cfg(feature = "alloc")]
|
||||
unsafe fn handle_signal(sig: c_int, info: siginfo_t, void: *mut c_void) {
|
||||
let signal = &Signal::try_from(sig).unwrap();
|
||||
let handler = {
|
||||
@ -385,6 +402,7 @@ unsafe fn handle_signal(sig: c_int, info: siginfo_t, void: *mut c_void) {
|
||||
///
|
||||
/// The signal handlers will be called on any signal. They should (tm) be async safe.
|
||||
/// A lot can go south in signal handling. Be sure you know what you are doing.
|
||||
#[cfg(feature = "alloc")]
|
||||
pub unsafe fn setup_signal_handler<T: 'static + Handler>(handler: &mut T) -> Result<(), Error> {
|
||||
// First, set up our own stack to be used during segfault handling. (and specify `SA_ONSTACK` in `sigaction`)
|
||||
if SIGNAL_STACK_PTR.is_null() {
|
||||
|
@ -1,5 +1,6 @@
|
||||
//! Exception handling for Windows
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::vec::Vec;
|
||||
use core::{
|
||||
cell::UnsafeCell,
|
||||
@ -282,6 +283,7 @@ pub static EXCEPTION_CODES_MAPPING: [ExceptionCode; 47] = [
|
||||
ExceptionCode::Other,
|
||||
];
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub trait Handler {
|
||||
/// Handle an exception
|
||||
fn handle(
|
||||
@ -366,6 +368,7 @@ unsafe extern "C" fn handle_signal(_signum: i32) {
|
||||
/// Setup Win32 exception handlers in a somewhat rusty way.
|
||||
/// # Safety
|
||||
/// Exception handlers are usually ugly, handle with care!
|
||||
#[cfg(feature = "alloc")]
|
||||
pub unsafe fn setup_exception_handler<T: 'static + Handler>(handler: &mut T) -> Result<(), Error> {
|
||||
let exceptions = handler.exceptions();
|
||||
let mut catch_assertions = false;
|
||||
|
@ -1,12 +1,13 @@
|
||||
//! A generic shared memory region to be used by any functions (queues or feedbacks
|
||||
//! too.)
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::{rc::Rc, string::ToString};
|
||||
use core::{
|
||||
cell::RefCell,
|
||||
fmt::{self, Debug, Display},
|
||||
mem::ManuallyDrop,
|
||||
};
|
||||
use core::fmt::Debug;
|
||||
#[cfg(feature = "alloc")]
|
||||
use core::fmt::Display;
|
||||
#[cfg(feature = "alloc")]
|
||||
use core::{cell::RefCell, fmt, mem::ManuallyDrop};
|
||||
#[cfg(feature = "std")]
|
||||
use std::env;
|
||||
#[cfg(all(unix, feature = "std"))]
|
||||
@ -105,6 +106,7 @@ impl ShMemId {
|
||||
}
|
||||
|
||||
/// Create a new id from an int
|
||||
#[cfg(feature = "alloc")]
|
||||
#[must_use]
|
||||
pub fn from_int(val: i32) -> Self {
|
||||
Self::from_string(&val.to_string())
|
||||
@ -140,6 +142,7 @@ impl ShMemId {
|
||||
}
|
||||
|
||||
/// Returns a `str` representation of this [`ShMemId`]
|
||||
#[cfg(feature = "alloc")]
|
||||
#[must_use]
|
||||
pub fn as_str(&self) -> &str {
|
||||
alloc::str::from_utf8(&self.id[..self.null_pos()]).unwrap()
|
||||
@ -152,12 +155,14 @@ impl AsSlice for ShMemId {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl From<ShMemId> for i32 {
|
||||
fn from(id: ShMemId) -> i32 {
|
||||
id.as_str().parse().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl Display for ShMemId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.as_str())
|
||||
@ -302,12 +307,14 @@ pub trait ShMemProvider: Clone + Default + Debug {
|
||||
/// A Reference Counted shared map,
|
||||
/// that can use internal mutability.
|
||||
/// Useful if the `ShMemProvider` needs to keep local state.
|
||||
#[cfg(feature = "alloc")]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RcShMem<T: ShMemProvider> {
|
||||
internal: ManuallyDrop<T::ShMem>,
|
||||
provider: Rc<RefCell<T>>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<T> ShMem for RcShMem<T>
|
||||
where
|
||||
T: ShMemProvider + Debug,
|
||||
@ -321,6 +328,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<T> AsSlice for RcShMem<T>
|
||||
where
|
||||
T: ShMemProvider + Debug,
|
||||
@ -331,6 +339,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<T> AsMutSlice for RcShMem<T>
|
||||
where
|
||||
T: ShMemProvider + Debug,
|
||||
@ -341,6 +350,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<T: ShMemProvider> Drop for RcShMem<T> {
|
||||
fn drop(&mut self) {
|
||||
self.provider.borrow_mut().release_shmem(&mut self.internal);
|
||||
|
@ -526,14 +526,28 @@ impl<Head, Tail> PlusOne for (Head, Tail) where
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{ownedref::OwnedMutSlice, tuples::type_eq};
|
||||
|
||||
/// An alias for equality testing
|
||||
type OwnedMutSliceAlias<'a> = OwnedMutSlice<'a, u8>;
|
||||
#[cfg(feature = "alloc")]
|
||||
use crate::ownedref::OwnedMutSlice;
|
||||
use crate::tuples::type_eq;
|
||||
|
||||
#[test]
|
||||
#[allow(unused_qualifications)] // for type name tests
|
||||
fn test_type_eq_simple() {
|
||||
// test eq
|
||||
assert!(type_eq::<u64, u64>());
|
||||
|
||||
// test neq
|
||||
assert!(!type_eq::<u64, usize>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "alloc")]
|
||||
#[allow(unused_qualifications)] // for type name tests
|
||||
fn test_type_eq() {
|
||||
// An alias for equality testing
|
||||
type OwnedMutSliceAlias<'a> = OwnedMutSlice<'a, u8>;
|
||||
|
||||
// A function for lifetime testing
|
||||
#[allow(clippy::extra_unused_lifetimes)]
|
||||
fn test_lifetimes<'a, 'b>() {
|
||||
assert!(type_eq::<OwnedMutSlice<'a, u8>, OwnedMutSlice<'b, u8>>());
|
||||
@ -545,12 +559,6 @@ mod test {
|
||||
assert!(type_eq::<OwnedMutSlice<u8>, OwnedMutSliceAlias>());
|
||||
|
||||
test_lifetimes();
|
||||
// test eq
|
||||
assert!(type_eq::<u64, u64>());
|
||||
|
||||
// test neq
|
||||
assert!(!type_eq::<u64, usize>());
|
||||
|
||||
// test weirder lifetime things
|
||||
assert!(type_eq::<OwnedMutSlice<u8>, OwnedMutSlice<u8>>());
|
||||
assert!(!type_eq::<OwnedMutSlice<u8>, OwnedMutSlice<u32>>());
|
||||
|
Loading…
x
Reference in New Issue
Block a user