Code Monkey home page Code Monkey logo

abi_stable_crates's People

Contributors

afranchuk avatar ahmed-masud avatar cad97 avatar gitter-badger avatar h33p avatar jean-airoldie avatar marioortizmanero avatar monadic-cat avatar rodrimati1992 avatar rustyyato avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

abi_stable_crates's Issues

StableAbi and Futures

First of all, thank you for your significant contribution to have a stable rust ABI. I found almost everything I needed except for working with futures. There is however another crate named asyncFfi, which provides #[repr(C)] alternative to future-structs.

I tried to have a NewType MyFuture(async_ffi::FfiFuture) which manually implements StableAbi, but I struggled to implement LAYOUT for it and I don't know if this is even possible. This leads to the following questions:

  1. Would you consider to have a feature-flag for this library, so FfiFuture implements StableAbi?
  2. Would it be possible to create a procedural macro to easily generate StableAbi-Implementations for any #[repr(C)] structs?
  3. If both 1+2 are not feasible: Is there another way to use FfiFuture in a StableAbi-struct?

Expose RRawMutex & RRawRwLock

I'm in the process of writing various async primitives with a stable ABI and I would need the equivalent of parking_lot::RawMutex & parking_lot::RawRwLock.

I see that what I would need would basically be those two internal types:

type OpaqueMutex=
UnsafeOveralignedField<RawMutex,[u8;OM_PADDING]>;

type OpaqueRwLock=
UnsafeOveralignedField<RawRwLock,[u8;OM_PADDING]>;

However there is no (easy) way for me to replicate these types since UnsafeOveralignedField is private.

Would you accept a PR if I turn these into fully fledged types with repr(C) and expose them publicly? It would implement lock_api::RawMutex.

As a side question, why are these fields overaligned over usize? Is it because we don't know the real size of the type ahead of time, but since it is a mutex we know that its size will never exceed a atomic usize?

Examples don't compile, and I need some help

I'm a bit new to rust, so maybe this isn't a great beginner project, but the examples don't compile, and they're a little complicated to understand, maybe some less-generic examples using "new" cargo workspaces would help.

I'm following working_with_abi_stable source which seems to compile and I mostly understand it.

I'm trying to expand my own project which interfaces with OSC to send and receive messages, and I want to send the received messages to all loaded plugins and allow plugins to send messages to the core application which will send them off via OSC.

This example tries to load libmin.so but each plugin would be under a different name such as libspotify.so or liblogger.so for example, how would I load multiple plugins that have the exact same interface? The example interface being MinMod and MinMod_Ref

Sharing thread-locals?

Is there a way to share thread-local variables?

Context

I'm trying to build a plugin system for swc ( https://swc.rs ) using abi_stable.

I want to provide exactly same api for plugin as core transforms, but core transforms use thread locals.

There are two important thread locals and both of them lives in swc_common.


I searched for thread local but failed to find one and thanks for a great library!

Making `abi_stable`'s types covariant

See #75 for an explanation as to why this issue needs to be resolved.

Here's an exhaustive list of the variance in std_types:

RCow

  • BorrowOwned should be removed (see #80)

RVec

  • buffer: *mut T should be changed to Unique<T>
  • vtable: VecVTable_Ref<T> should be made opaque

RHashMap

  • map: RBox<ErasedMap<K, V, S>> requires fixing RBox<T> first
  • vtable: VTable_Ref<K, V, S> should be made opaque

RBox

  • data: *mut T should be changed to Unique<T>
  • vtable: BoxVtable_Ref<T> should be made opaque

RArc

  • vtable: ArcVtable_Ref<T> should be made opaque

The rest

  • RBoxError_, RIoError, RIoErrorKind, RString, UTypeId, RDuration, RCmpOrdering, RSeekFrom: no generic parameters
  • RSliceMut: should be left as invariant
  • RStr, RSlice, Tuple{1..4}, ROption, RResult: already covariant

Thoughts

About *mut T:

  • Most of the changes to Unique<T> can work fine with NonNull<T> as well. However, NonNull<T> has weaker semantics than Unique<T>, and we can actually guarantee that the pointer is owned by that struct.

About the vtables:

  • We can use mem::transmute over the vtable itself, rather than over each individual function it has.
  • We should use ErasedType instead of *const () for the opaque types, right?
  • Can we make this an easier & safer task? For example, having an option in the vtable proc macros. Definitely for the future, though.
  • Is it possible to avoid the transmute?

Others:

  • We should add a new test file to make sure everything's covariant. And also make sure the new unsafe is documented properly.

@rodrimati1992, we can split up the work however you like, and if you have any advice, please let me know. Specially regarding how to fix the vtables properly, which I'm not quite sure how to do best.

`StableAbi` for `c_void`

Hey there, I'm attempting to integrate your (awesome) layout checking with CGlue. It seems like core::ffi::c_void does not have StableAbi implemented, though, which causes some problems. I currently have it hackfixed by borrowing the () implementation, but it would be really cool to have it upstream. I can go ahead and submit a PR if you'd like, but am not exactly certain which fields need to be customized apart from name and module strings.

`extern` block uses type `NotCopyNotClone`, which is not FFI-safe

Hi, i'm trying to implement sdk for my plugin system. In an application side i'm define a function:

#[sabi_extern_fn]
pub fn info_version() -> RString {
    VersionInfo::current().to_string().into()
}

In a plugin side i'm trying to use it like:

extern "C" {
    fn info_version() -> RString;
}

There is warnings when compiling with rustc 1.78.0:

warning: `extern` block uses type `NotCopyNotClone`, which is not FFI-safe
 --> sdk/info.rs:4:26
  |
4 |     fn info_version() -> RString;
  |                          ^^^^^^^ not FFI-safe
  |
  = help: consider adding a member to this struct
  = note: this struct has no fields
  = note: `#[warn(improper_ctypes)]` on by default

[Question] What is the sequence diagram using the readme interface example ?

Dear,

Thanks for your works,
I am trying to understand how this crate works, thus I have some questions:

  1. At which time the plugin .so file is loaded ?
  2. about of load_from_directory function used into the example interface line 54 , what do this function. Does it try to load any .so file from given directory ?

Below my actual and fuzzy understanding

sequenceDiagram
participant App
participant MyPluginInterface
participant MyPlugin
participant RootModule as  abi_stable::library::RootModule
App ->> MyPluginInterface : use specialized defined API
MyPluginInterface ->> MyPlugin : call load_from_directory
MyPlugin ->> RootModule : call load_from_directory
RootModule  -> MysharedLib : load .so file

I would like to achieve something like:
An App which define various interfaces to let other dev extend the app via various plugins
So, the App do not know implementations (i.e the plugins) but know that plugins are all located into my/plugin/dir
The App loop over plugin into my/plugin/dir and load them

What it is blocking while reading example ?
In readme_example The readme_user app use readme_interface which implement RootModule
To my understanding at this step the interface define the plugin name that would mean into one directory only one plugin using this interface is possible, no ?

Edit: for the last part I think I understood, I should not create 1 interface by plugin but 1 interface for all kind of plugin and use the same way describe into 1_trait_objects

Thanks for your insight

Builds fail on 32-bit platforms

When attempting to build for some PowerPC 32 bit platforms, I am running into issues with abi_stable/src/abi_stability/stable_abi_trait.rs lines 1198 and 1202 attempting to use 64-bit atomic types.

I think this is easily addressed once Rust compilers support target_has_atomic, but that appears to be a month or two away. Below is a patch I am temporarily using. I am hoping abi_stable will be able to address this soon, possibly shortly after stabilization of target_has_atomic.

--- a/vendor/abi_stable_crates/abi_stable/src/abi_stability/stable_abi_trait.rs
+++ b/vendor/abi_stable_crates/abi_stable/src/abi_stability/stable_abi_trait.rs
@@ -1195,10 +1195,31 @@ mod rust_1_34_impls {
             (AtomicI8 ,"AtomicI8" ,i8,"std::sync::atomic"),
             (AtomicI16,"AtomicI16",i16,"std::sync::atomic"),
             (AtomicI32,"AtomicI32",i32,"std::sync::atomic"),
-            (AtomicI64,"AtomicI64",i64,"std::sync::atomic"),
             (AtomicU8 ,"AtomicU8" ,u8,"std::sync::atomic"),
             (AtomicU16,"AtomicU16",u16,"std::sync::atomic"),
             (AtomicU32,"AtomicU32",u32,"std::sync::atomic"),
+        ]
+    }
+
+    // This is similar to serde's build.rs, but uses target_arch.
+    // We don't use starts.with() because this isn't build.rs .
+    // We would prefer to use #[cfg(target_has_atomic = "64")], but
+    // that's not yet stable.  (Perhaps with rustc v1.64.0.)
+    //
+    // See: https://docs.rs/platforms/latest/platforms/enum.Arch.html
+    // and https://github.com/serde-rs/serde/blob/master/serde/build.rs#L94-L103
+    #[cfg(any(
+        target_arch = "aarch64",
+        target_arch = "mips64",
+        target_arch = "powerpc64",
+        target_arch = "riscv64",
+        target_arch = "sparc64",
+        target_arch = "x86_64"
+    ))]
+    impl_for_concrete! {
+        type IsNonZeroType=False;
+        [
+            (AtomicI64,"AtomicI64",i64,"std::sync::atomic"),
             (AtomicU64,"AtomicU64",u64,"std::sync::atomic"),
         ]
     }

(I am also having a similar issue with crossbeam, but I am able to workaround that by removing the "channels" feature.)

Possible collaboration with Pipeline IDE?

We are planning an eventual implementation of the Pipeline IDE graph execution for Rust. (Now it is only for Solidity and JS.) Your work here could be helpful, but I do not know Rust enough to know clearly how to use abi_stable_crates and to interface it into our work.

I can envision this as the ability to weave new functions and dylibs by using funcs already deployed in dylibs. All without writing a line of code: just visually editing the graph. Interesting and doable?

https://www.youtube.com/watch?v=-LHvdZZUrss

https://github.com/pipeos-one/pipeline

Any guidance is appreciated.

`abi_stable::sabi_trait` triggering `repr_transparent_external_private_fields` warning with latest nightly rustc

After upgrading my rustc to rustc 1.65.0-nightly (2befdefdd 2022-08-06), following warning appeared and I think it should be fixed.

   |
60 | #[abi_stable::sabi_trait]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: `#[warn(repr_transparent_external_private_fields)]` on by default
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
   = note: this struct contains `UnsafeIgnoredType<SyncSend>`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
   = note: this warning originates in the attribute macro `abi_stable::sabi_trait` (in Nightly builds, run with -Z macro-backtrace for more info)

Crate relies on implicit promotion of `const fn` calls

There are plans to change the rules for implicit promotion such that calls to const fn are not implicitly promoted to 'static lifetime any more. A crater experiment showed that only very few crates would be affected by this change, and this is one of them.

You can see an example of the relevant build failure here. Usually there is a way to work around this by explicitly putting the intermediate result into a const, of which a reference is then taken. However, since this is macro-generated code, I was unable to find the right spot(s) in the code where this would have to be done.

Stable ABI for floating point numbers

I've noticed that there's an implementation of StableAbi for most basic types, such as i32, u64, etc with the impl_for_primitive_ints macro. However, f64 isn't in that list, and neither is f32. In fact, f64 isn't mentioned once in the whole repository.

If it helps, their size is always known as per the reference: https://doc.rust-lang.org/stable/reference/type-layout.html#primitive-data-layout. But it's true that they don't have a known representation: https://doc.rust-lang.org/stable/reference/type-layout.html#primitive-representations.

I'm guessing I have to use std::os::raw::c_double and std::os::raw::c_float instead of f64, but is there any way to make this easier to use? It seems to just be an alias to Rust's type (https://doc.rust-lang.org/std/os/raw/type.c_float.html), but I'm not sure if there are any guarantees.

Thanks!

Adding a map type.

This project needs a map type of some sort,and I can see some possibilities to how it could be implemented:

  1. Just wrap the regular standard map types,using type erasure and passing them to a vtable to call any method that uses Hash (for the hash implementation has to be consistent,it has to be a dyamically dispatched function).

  2. Implement a map type from scratch.

  3. Port the standard library one,replacing every internal type with #[repr(C)] and adding #[derive(StableAbi)].

lifetimes with R* types break compared to non R* types

Hi,
sorry for the bad title, I'm not sure how to phrase the issue in a concise one-line description.

It seems that something inside abi_stables R* types breaks rusts lifetime tracking. We (@marioortizmanero and the rest of the tremor team) went through the attempt of using them for internal data as part of his PDK project and got to the point where a lot of lifetime errors (the nasty kind) were thrown up.

Initially, we suspected that we had done something wrong in the interpreter using the data so we tried to find the underlying cause and boiled it down to (hopefully) one initial issue that doesn't require to go through 1000s of lines of code :)

Basically, the following code

use abi_stable::std_types::RCow;
use std::borrow::Cow;

fn cmp_cow<'a, 'b>(left: &Cow<'a, ()>, right: &Cow<'b, ()>) -> bool {
    left == right
}

fn cmp_rcow<'a, 'b>(left: &RCow<'a, ()>, right: &RCow<'b, ()>) -> bool {
    left == right
}

fn main() {
    println!("Hello, world!");
}

fails with the following error:

    Checking repro v0.1.0 (/home/heinz/mario/repro)
error[E0623]: lifetime mismatch
 --> src/main.rs:9:10
  |
8 | fn cmp_rcow<'a, 'b>(left: &RCow<'a, ()>, right: &RCow<'b, ()>) -> bool {
  |                            ------------          ------------
  |                            |
  |                            these two types are declared with different lifetimes...
9 |     left == right
  |          ^^ ...but data from `left` flows into `right` here

For more information about this error, try `rustc --explain E0623`.
error: could not compile `repro` due to previous error

We could reproduce the same for RVec, and RHashMap as long they contained a lifetime.

Below a more extensive test with a number of other types:

use abi_stable::std_types::{RCow, RHashMap, RSlice, RStr, RString, RVec, Tuple2};
use std::{borrow::Cow, collections::HashMap};

fn cmp_string<'a, 'b>(left: &String, right: &String) -> bool {
    left == right
}
fn cmp_rstring<'a, 'b>(left: &RString, right: &RString) -> bool {
    left == right
}

fn cmp_str<'a, 'b>(left: &'a str, right: &'b str) -> bool {
    left == right
}
fn cmp_rstr<'a, 'b>(left: &RStr<'a>, right: &RStr<'b>) -> bool {
    left == right
}

fn cmp_vec<'a, 'b>(left: &Vec<&'a str>, right: &Vec<&'b str>) -> bool {
    left == right
}
fn cmp_rvec<'a, 'b>(left: &RVec<&'a str>, right: &RVec<&'b str>) -> bool {
    left == right
}

fn cmp_tpl<'a, 'b>(left: &(&'a str, u8), right: &(&'b str, u8)) -> bool {
    left == right
}
fn cmp_rtpl<'a, 'b>(left: &Tuple2<&'a str, u8>, right: &Tuple2<&'b str, u8>) -> bool {
    left == right
}

fn cmp_slice<'a, 'b>(left: &[&'a str], right: &[&'b str]) -> bool {
    left == right
}
fn cmp_rslice<'a, 'b>(left: &RSlice<&'a str>, right: &RSlice<&'b str>) -> bool {
    left == right
}
fn cmp_cow<'a, 'b>(left: &Cow<'a, ()>, right: &Cow<'b, ()>) -> bool {
    left == right
}
fn cmp_rcow<'a, 'b>(left: &RCow<'a, ()>, right: &RCow<'b, ()>) -> bool {
    left == right
}

fn cmp_hashmap<'a, 'b>(left: &HashMap<&'a str, ()>, right: &HashMap<&'a str, ()>) -> bool {
    left == right
}
fn cmp_rhashmap<'a, 'b>(left: &RHashMap<u8, &'a str>, right: &RHashMap<u8, &'b str>) -> bool {
    left == right
}

fn main() {
    println!("Hello, world!");
}

Mutating fields of prefix types

Maybe it's not an intended usage, but I'm curious if you have a plan to support mutating fields of Prefix types.
It's required to preserve compatibility of rust-based swc plguins.

Update unsound DrainFilter and RString::retain

Hello, we (Rust group @sslab-gatech) found a memory-safety/soundness issue in this crate while scanning Rust code on crates.io for potential vulnerabilities.

impl<T, F> Iterator for DrainFilter<'_, T, F>
where F: FnMut(&mut T) -> bool,
{
type Item = T;
fn next(&mut self) -> Option<T> {
unsafe {
while self.idx != self.old_len {
let i = self.idx;
self.idx += 1;
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
if (self.pred)(&mut v[i]) {
self.del += 1;
return Some(ptr::read(&v[i]));
} else if self.del > 0 {
let del = self.del;
let src: *const T = &v[i];
let dst: *mut T = &mut v[i - del];
ptr::copy_nonoverlapping(src, dst, 1);
}
}
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.old_len - self.idx))
}
}

#[inline]
pub fn retain<F>(&mut self, mut pred: F)
where F: FnMut(char) -> bool
{
// literal copy-paste of std,so if this is wrong std is wrong.
let len = self.len();
let mut del_bytes = 0;
let mut idx = 0;
while idx < len {
let ch = unsafe {
self.get_unchecked(idx..len).chars().next().unwrap()
};
let ch_len = ch.len_utf8();
if !pred(ch) {
del_bytes += ch_len;
} else if del_bytes > 0 {
unsafe {
ptr::copy(
self.inner.as_ptr().add(idx),
self.inner.as_mut_ptr().add(idx - del_bytes),
ch_len
);
}
}
idx += ch_len;
}
if del_bytes > 0 {
unsafe { self.inner.set_len(len - del_bytes); }
}
}

These two implementations are copy-pasted from Rust's standard library, and unfortunately it turns out that std implementations were containing soundness bugs (rust-lang/rust#60977 and rust-lang/rust#78498, respectively). Could you check them and update the respective part of this crate?

Providing examples for methods of abi_stable::std_types types.

I haven't added any examples to std_type types since most of them are identical to the std library ones.
If anyone wants to add examples,it should be easy enough to do for functions/methods that are identical to std library ones.
If you want to add examples please comment here before you do so.

Build broken on <=1.45.0

Hey there, it seems like 0.10 build is broken on older versions of Rust. The issue stems from several const fns in nul_str.rs that do branching. 0.9 works fine. Seems like travis-ci does not do any builds.

Inconsistency between documentation and code implementation

I noticed a possible panics due to inconsistency between documentation and code implementation in abi_stable/src/type_layout/tl_functions.rs. The details can be found in the following code. The code does not check whether nth is out of bounds before using [nth].

/// # Panics
///
/// This function panics if `nth` is out of bounds
/// (when `nth` is greater than or equal to `self.len()`)
pub fn index(&'static self, nth: usize, shared_vars: &'static SharedVars) -> TLFunction {
        self.functions()[nth].expand(shared_vars)
}

Efficient type identification scheme

Hey there, using abi_stable I've noticed significant size requirements for performing layout checks. It appears to stem from indirection caused by accessing type IDs and layouts within TypeLayout and SharedVars through ctors. This leads to explosion of tiny functions bloating the binary/library size. If I am not mistaken, this was done due to self-referential structures and it being impossible for the compiler to deal with.

I tinkered a little bit, trying to see if one could come up with a way to support self-referential structures while staying completely in compile-time, and here is a little PoC:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=1e622b3aea8aa4437a25cae2646de820

The trick here is to have 2 type IDs, one that evaluates IDs within its type, and the other "shallow" one that skips the contents of the type. This way everything is evaluated until the last type, however, this still does not solve the self-referential cycles. The latter is solved by providing special implementations for all 4 types of indirection available in rust (mut/const references and pointers) that use only the shallow type ID. This works, because T: StableAbi implies &T: StableAbi. The example works with generating unique Type IDs, however, I think it would similarly be able to be extended over to TypeLayouts as well. Finally, it may even be possible to reduce a lot of type checking into a single stable hash value.

The question is, would the implementation of this be in your interest? I believe this would lead to positive impact to all abi_stable users and am willing to implement it, however, it would be great to do it in cooperation, as I do not want to miss out on key details regarding prefix types, reflection, etc.

Document recommendations for using crates that have std types in public interface

Perhaps I've missed an important part of the documentation, but it seems to me that using this crate with other crates that use std types in public api involves a lot of copying.

For example if I have a crate that manipulates Vec-s from the standard library and I then want to make those Vec-s accessible over ABI then I have no option other than to make a copy to RVec, which could be really bad for performance if the Vec-s are large.

Is this assessment accurate? Are the tradeoffs and recommendations for these kinds of situations documented somewhere? If not it would be useful if they were.

Generating C bindings

Hello,

Would it be possible to work on generating C bindings for this crate? Considering this is used for plugin systems, it could be handy to have a C header available for compatibility with other programming languages, as an extra for having a stable ABI.

I've tried using cbindgen:

Full output
/tmp/abi_stable_crates/abi_stable master
❯ cbindgen --lang=C .
WARN: Skip abi_stable::LIB_HEADER - (not `no_mangle`).
WARN: Skip abi_stable::ABI_STABLE_VERSION - (Unsupported expression. Macro(ExprMacro { attrs: [], mac: Macro { path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(package_version_strings), arguments: None }] }, bang_token: Bang, delimiter: Paren(Paren), tokens: TokenStream [] } }))
WARN: Skip abi_stable::EXECUTABLE_IDENTITY - (not `pub`).
WARN: Skip abi_stable::EXECUTABLE_IDENTITY - (not `no_mangle`).
WARN: Skipping abi_stable::get_type_name - (not `no_mangle`, and has no `export_name` attribute)
WARN: Skip abi_stable::EMPTY - (not `pub`).
WARN: Skip abi_stable::BASE_NAME - (not `pub`).
WARN: Skipping abi_stable::check_layout_compatibility_for_ffi - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::exported_check_layout_compatibility - (not `no_mangle`, and has no `export_name` attribute)
WARN: Skip abi_stable::CHECKING_GLOBALS - (not `pub`).
WARN: Skip abi_stable::CHECKING_GLOBALS - (not `no_mangle`).
WARN: Skip abi_stable::_VTABLE_STATIC - (not `pub`).
WARN: Skipping abi_stable::get_type_layout - (not `no_mangle`, and has no `export_name` attribute)
WARN: Skipping abi_stable::get_prefix_field_type_layout - (not `no_mangle`, and has no `export_name` attribute)
WARN: Skip abi_stable::UNSAFE_EXTERN_FN_LAYOUT - (Unsupported path expression. [PathSegment { ident: Ident(GetTypeLayoutCtor), arguments: AngleBracketed(AngleBracketedGenericArguments { colon2_token: Some(Colon2), lt_token: Lt, args: [Type(BareFn(TypeBareFn { lifetimes: None, unsafety: Some(Unsafe), abi: Some(Abi { extern_token: Extern, name: Some(LitStr { token: "C" }) }), fn_token: Fn, paren_token: Paren, inputs: [], variadic: None, output: Default }))], gt_token: Gt }) }, Colon2, PathSegment { ident: Ident(STABLE_ABI), arguments: None }])
WARN: Skip abi_stable::EXTERN_FN_LAYOUT - (Unsupported path expression. [PathSegment { ident: Ident(GetTypeLayoutCtor), arguments: AngleBracketed(AngleBracketedGenericArguments { colon2_token: Some(Colon2), lt_token: Lt, args: [Type(BareFn(TypeBareFn { lifetimes: None, unsafety: None, abi: Some(Abi { extern_token: Extern, name: Some(LitStr { token: "C" }) }), fn_token: Fn, paren_token: Paren, inputs: [], variadic: None, output: Default }))], gt_token: Gt }) }, Colon2, PathSegment { ident: Ident(STABLE_ABI), arguments: None }])
WARN: Skip abi_stable::STABLE_ABI - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(Constructor), arguments: None }] } }), paren_token: Paren, args: [Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(get_type_layout), arguments: AngleBracketed(AngleBracketedGenericArguments { colon2_token: Some(Colon2), lt_token: Lt, args: [Type(Path(TypePath { qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(T), arguments: None }] } }))], gt_token: Gt }) }] } }), Comma] }))
WARN: Skip abi_stable::SABI_OPAQUE_FIELD - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(Constructor), arguments: None }] } }), paren_token: Paren, args: [Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(get_type_layout), arguments: AngleBracketed(AngleBracketedGenericArguments { colon2_token: Some(Colon2), lt_token: Lt, args: [Type(Path(TypePath { qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(UnsafeOpaqueField), arguments: AngleBracketed(AngleBracketedGenericArguments { colon2_token: None, lt_token: Lt, args: [Type(Path(TypePath { qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(T), arguments: None }] } }))], gt_token: Gt }) }] } }))], gt_token: Gt }) }] } }), Comma] }))
WARN: Skip abi_stable::PREFIX_STABLE_ABI - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(Constructor), arguments: None }] } }), paren_token: Paren, args: [Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(get_prefix_field_type_layout), arguments: AngleBracketed(AngleBracketedGenericArguments { colon2_token: Some(Colon2), lt_token: Lt, args: [Type(Path(TypePath { qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(T), arguments: None }] } }))], gt_token: Gt }) }] } }), Comma] }))
WARN: Skip abi_stable::OPAQUE_FIELD - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(Constructor), arguments: None }] } }), paren_token: Paren, args: [Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(get_type_layout), arguments: AngleBracketed(AngleBracketedGenericArguments { colon2_token: Some(Colon2), lt_token: Lt, args: [Type(Path(TypePath { qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(UnsafeOpaqueField), arguments: AngleBracketed(AngleBracketedGenericArguments { colon2_token: None, lt_token: Lt, args: [Type(Path(TypePath { qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(T), arguments: None }] } }))], gt_token: Gt }) }] } }))], gt_token: Gt }) }] } }), Comma] }))
WARN: Skip abi_stable::LAYOUT - (not `pub`).
WARN: Skip abi_stable::LAYOUT - (not `pub`).
WARN: Skip abi_stable::LAYOUT - (not `pub`).
WARN: Skip abi_stable::LAYOUT - (not `pub`).
WARN: Skip abi_stable::LAYOUT - (not `pub`).
WARN: Skip abi_stable::LAYOUT - (not `pub`).
WARN: Skip abi_stable::LAYOUT - (not `pub`).
WARN: Skip abi_stable::LAYOUT - (not `pub`).
WARN: Couldn't find path for FuncPtr { ret: Primitive(Void), args: [], is_nullable: false }, skipping associated constants
WARN: Couldn't find path for FuncPtr { ret: Primitive(Void), args: [], is_nullable: false }, skipping associated constants
WARN: Skip abi_stable::LAYOUT - (not `pub`).
WARN: Skip abi_stable::LAYOUT - (not `pub`).
WARN: Skip abi_stable::LAYOUT - (not `pub`).
WARN: Skipping abi_stable::drop_pointer_impl - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::clone_pointer_impl - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::default_pointer_impl - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::display_impl - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::debug_impl - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::serialize_impl - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::partial_eq_impl - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::cmp_ord - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::partial_cmp_ord - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::hash_Hash - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::hash_slice_Hasher - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::finish_Hasher - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::write_str_fmt_write - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::io_Write_write - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::io_Write_write_all - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::io_Write_flush - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::io_Read_read - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::io_Read_read_exact - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::io_BufRead_fill_buf - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::io_BufRead_consume - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::io_Seek_seek - (not `pub` but is `extern "C"`)
WARN: Skip abi_stable::NEW - (not `pub`).
WARN: Skip abi_stable::NEW - (not `pub`).
WARN: Skip abi_stable::NEW - (not `pub`).
WARN: Skip abi_stable::NEW - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(Self), arguments: None }] } }), paren_token: Paren, args: [Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(PhantomData), arguments: None }] } })] }))
WARN: Skip abi_stable::NEW - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(Self), arguments: None }] } }), paren_token: Paren, args: [Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(PhantomData), arguments: None }] } })] }))
WARN: Skipping abi_stable::next - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::extending_rvec - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::size_hint - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::count - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::last - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::nth - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::skip_eager - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::next_back - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::extending_rvec_back - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::nth_back - (not `pub` but is `extern "C"`)
WARN: Skip abi_stable::ITER - (not `pub`).
WARN: Skip abi_stable::ITER - (not `pub`).
WARN: Skip abi_stable::JSON_0 - (Unsupported literal expression. Str(LitStr { token: r#"
    {
        "l":1000,
        "r":10,
        "name":"what the hell"
    }
"# }))
WARN: Skip abi_stable::INFO - (not `pub`).
WARN: Skip abi_stable::INFO - (not `pub`).
WARN: Skip abi_stable::GET - (Unsupported path expression. [PathSegment { ident: Ident(GetVtable), arguments: AngleBracketed(AngleBracketedGenericArguments { colon2_token: None, lt_token: Lt, args: [Lifetime(Lifetime { apostrophe: Span, ident: Ident(borr) }), Comma, Type(Path(TypePath { qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(T), arguments: None }] } })), Comma, Type(Path(TypePath { qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(ErasedPtr), arguments: None }] } })), Comma, Type(Path(TypePath { qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(OrigPtr), arguments: None }] } })), Comma, Type(Path(TypePath { qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(I), arguments: None }] } }))], gt_token: Gt }) }, Colon2, PathSegment { ident: Ident(_GET_INNER_VTABLE), arguments: None }])
WARN: Skip abi_stable::INFO - (not `pub`).
WARN: Skip abi_stable::VALUE - (not `pub`).
WARN: Skip abi_stable::MS - (not `pub`).
WARN: Skip abi_stable::RAW_LOCK_SIZE - (not `pub`).
WARN: Skip abi_stable::OM_PADDING - (not `pub`).
WARN: Skip abi_stable::OPAQUE_ONCE - (not `pub`).
WARN: Skipping abi_stable::state - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::call_once - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::call_once_force - (not `pub` but is `extern "C"`)
WARN: Skip abi_stable::NEW - (Unsupported path expression. [PathSegment { ident: Ident(VTable), arguments: None }, Colon2, PathSegment { ident: Ident(VTABLE), arguments: None }])
WARN: Skip abi_stable::VTABLE - (not `pub`).
WARN: Skip abi_stable::OM_PADDING - (not `pub`).
WARN: Skip abi_stable::OPAQUE_MUTEX - (not `pub`).
WARN: Skipping abi_stable::lock - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::try_lock - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::unlock - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::try_lock_for - (not `pub` but is `extern "C"`)
WARN: Skip abi_stable::_TMP0 - (not `pub`).
WARN: Skip abi_stable::ITERS - (not `pub`).
WARN: Skip abi_stable::ITERS - (not `pub`).
WARN: Skip abi_stable::OM_PADDING - (not `pub`).
WARN: Skip abi_stable::OPAQUE_LOCK - (not `pub`).
WARN: Skipping abi_stable::lock_shared - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::try_lock_shared - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::try_lock_shared_for - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::unlock_shared - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::lock_exclusive - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::try_lock_exclusive - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::try_lock_exclusive_for - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::unlock_exclusive - (not `pub` but is `extern "C"`)
WARN: Skip abi_stable::_TMP0 - (not `pub`).
WARN: Skip abi_stable::EXPECTED - (not `pub`).
WARN: Skip abi_stable::C_ABI_TESTING_FNS - (Unsupported expression. Reference(ExprReference { attrs: [], and_token: And, raw: Reserved, mutability: None, expr: Struct(ExprStruct { attrs: [], path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(CAbiTestingFns), arguments: None }] }, brace_token: Brace, fields: [FieldValue { attrs: [], member: Named(Ident(take_pair_a)), colon_token: None, expr: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(take_pair_a), arguments: None }] } }) }, Comma, FieldValue { attrs: [], member: Named(Ident(take_pair_b)), colon_token: None, expr: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(take_pair_b), arguments: None }] } }) }, Comma, FieldValue { attrs: [], member: Named(Ident(ret_pair_a)), colon_token: None, expr: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(ret_pair_a), arguments: None }] } }) }, Comma, FieldValue { attrs: [], member: Named(Ident(ret_pair_b)), colon_token: None, expr: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(ret_pair_b), arguments: None }] } }) }, Comma, FieldValue { attrs: [], member: Named(Ident(take_triple_a)), colon_token: None, expr: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(take_triple_a), arguments: None }] } }) }, Comma, FieldValue { attrs: [], member: Named(Ident(take_triple_b)), colon_token: None, expr: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(take_triple_b), arguments: None }] } }) }, Comma, FieldValue { attrs: [], member: Named(Ident(take_triple_c)), colon_token: None, expr: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(take_triple_c), arguments: None }] } }) }, Comma, FieldValue { attrs: [], member: Named(Ident(ret_triple_a)), colon_token: None, expr: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(ret_triple_a), arguments: None }] } }) }, Comma, FieldValue { attrs: [], member: Named(Ident(ret_triple_b)), colon_token: None, expr: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(ret_triple_b), arguments: None }] } }) }, Comma, FieldValue { attrs: [], member: Named(Ident(ret_triple_c)), colon_token: None, expr: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(ret_triple_c), arguments: None }] } }) }, Comma, FieldValue { attrs: [], member: Named(Ident(take_2_pairs_a)), colon_token: None, expr: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(take_2_pairs_a), arguments: None }] } }) }, Comma, FieldValue { attrs: [], member: Named(Ident(take_2_pairs_b)), colon_token: None, expr: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(take_2_pairs_b), arguments: None }] } }) }, Comma, FieldValue { attrs: [], member: Named(Ident(ret_2_pairs_a)), colon_token: None, expr: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(ret_2_pairs_a), arguments: None }] } }) }, Comma, FieldValue { attrs: [], member: Named(Ident(ret_2_pairs_b)), colon_token: None, expr: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(ret_2_pairs_b), arguments: None }] } }) }, Comma, FieldValue { attrs: [], member: Named(Ident(mixed_units)), colon_token: None, expr: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(mixed_units), arguments: None }] } }) }, Comma], dot2_token: None, rest: None }) }))
WARN: Skipping abi_stable::take_pair_a - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::take_pair_b - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::ret_pair_a - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::ret_pair_b - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::take_triple_a - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::take_triple_b - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::take_triple_c - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::ret_triple_a - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::ret_triple_b - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::ret_triple_c - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::take_2_pairs_a - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::take_2_pairs_b - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::ret_2_pairs_a - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::ret_2_pairs_b - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::mixed_units - (not `pub` but is `extern "C"`)
WARN: Skip abi_stable::INIT_GLOBALS_WITH - (not `pub`).
WARN: Skip abi_stable::ABORTING_CONSTRUCTOR - (not `pub`).
WARN: Skip abi_stable::VALUE - (Unsupported expression. Block(ExprBlock { attrs: [], label: None, block: Block { brace_token: Brace, stmts: [Item(Mod(ItemMod { attrs: [], vis: Inherited, mod_token: Mod, ident: Ident(value), content: Some((Brace, [Use(ItemUse { attrs: [], vis: Inherited, use_token: Use, leading_colon: None, tree: Path(UsePath { ident: Ident(super), colon2_token: Colon2, tree: Glob(UseGlob { star_token: Star }) }), semi_token: Semi }), Macro(ItemMacro { attrs: [], ident: None, mac: Macro { path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(abi_stable_derive), arguments: None }, Colon2, PathSegment { ident: Ident(construct_abi_header), arguments: None }] }, bang_token: Bang, delimiter: Brace(Brace), tokens: TokenStream [] }, semi_token: None })])), semi: None })), Expr(Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(value), arguments: None }, Colon2, PathSegment { ident: Ident(ABI_HEADER), arguments: None }] } }))] } }))
WARN: Skip abi_stable::NEW - (Unsupported path expression. [PathSegment { ident: Ident(UnsafeIgnoredType), arguments: None }, Colon2, PathSegment { ident: Ident(NEW), arguments: None }])
WARN: Skip abi_stable::NEW - (Unsupported path expression. [PathSegment { ident: Ident(UnsafeIgnoredType), arguments: None }, Colon2, PathSegment { ident: Ident(NEW), arguments: None }])
WARN: Skip abi_stable::NEW - (Unsupported path expression. [PathSegment { ident: Ident(UnsyncUnsend), arguments: None }, Colon2, PathSegment { ident: Ident(NEW), arguments: None }])
WARN: Skip abi_stable::LAYOUT - (not `pub`).
WARN: Skip abi_stable::DEFAULT - (Unsupported expression. Array(ExprArray { attrs: [], bracket_token: Bracket, elems: [] }))
WARN: Skip abi_stable::NEW - (Unsupported expression. Array(ExprArray { attrs: [], bracket_token: Bracket, elems: [] }))
WARN: Skip abi_stable::LAYOUT - (not `pub`).
WARN: Skip abi_stable::DEFAULT - (Unsupported expression. Array(ExprArray { attrs: [], bracket_token: Bracket, elems: [] }))
WARN: Skip abi_stable::NEW - (Unsupported expression. Array(ExprArray { attrs: [], bracket_token: Bracket, elems: [] }))
WARN: Skip abi_stable::LAYOUT - (not `pub`).
WARN: Skip abi_stable::VTABLE_VAL - (not `pub`).
WARN: Skipping abi_stable::drop_impl - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::clone_impl - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::partial_eq_impl - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::cmp_ord - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::partial_cmp_ord - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::serialize_impl - (not `pub` but is `extern "C"`)
WARN: Skip abi_stable::VALUE - (not `pub`).
WARN: Skip abi_stable::VALUE - (not `pub`).
WARN: Skip abi_stable::VALUE - (not `pub`).
WARN: Skip abi_stable::NEW - (Unsupported path expression. [PathSegment { ident: Ident(PrefixTypeTrait), arguments: None }, Colon2, PathSegment { ident: Ident(METADATA), arguments: None }])
WARN: Skip abi_stable::NAME - (not `pub`).
WARN: Skip abi_stable::NAME - (not `pub`).
WARN: Skip abi_stable::LAYOUT - (not `pub`).
WARN: Skip abi_stable::EMPTY - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(Self), arguments: None }, Colon2, PathSegment { ident: Ident(new), arguments: None }] } }), paren_token: Paren, args: [Lit(ExprLit { attrs: [], lit: Int(LitInt { token: 0 }) }), Comma, Lit(ExprLit { attrs: [], lit: Int(LitInt { token: 0 }) })] }))
WARN: Skip abi_stable::None - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(OptionU16), arguments: None }] } }), paren_token: Paren, args: [Unary(ExprUnary { attrs: [], op: Not(Bang), expr: Lit(ExprLit { attrs: [], lit: Int(LitInt { token: 0 }) }) })] }))
WARN: Skip abi_stable::MAX_VAL - (not `pub`).
WARN: Skip abi_stable::None - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(OptionU8), arguments: None }] } }), paren_token: Paren, args: [Unary(ExprUnary { attrs: [], op: Not(Bang), expr: Lit(ExprLit { attrs: [], lit: Int(LitInt { token: 0 }) }) })] }))
WARN: Skip abi_stable::MAX_VAL - (not `pub`).
WARN: Skip abi_stable::GET_ERR - (not `pub`).
WARN: Skip abi_stable::RECURSIVE_INDICATOR - (not `pub`).
WARN: Skip abi_stable::NULL - (Unsupported expression. Reference(ExprReference { attrs: [], and_token: And, raw: Reserved, mutability: None, expr: Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(Tag), arguments: None }, Colon2, PathSegment { ident: Ident(null), arguments: None }] } }), paren_token: Paren, args: [] }) }))
WARN: Skip abi_stable::TAG_SET_EMPTY - (not `pub`).
WARN: Skip abi_stable::TAG_ARR_EMPTY - (not `pub`).
WARN: Skip abi_stable::TAG_SET_0 - (not `pub`).
WARN: Skip abi_stable::TAG_ARR_0 - (not `pub`).
WARN: Skip abi_stable::TAG_1_ORDER_0_VALUE - (not `pub`).
WARN: Skip abi_stable::TAG_SET_1_ORDER_0 - (not `pub`).
WARN: Skip abi_stable::TAG_ARR_1_ORDER_0 - (not `pub`).
WARN: Skip abi_stable::TAG_1_ORDER_1_VALUE - (not `pub`).
WARN: Skip abi_stable::TAG_SET_1_ORDER_1 - (not `pub`).
WARN: Skip abi_stable::TAG_ARR_1_ORDER_1 - (not `pub`).
WARN: Skip abi_stable::TAG_2_VALUE - (not `pub`).
WARN: Skip abi_stable::TAG_SET_2 - (not `pub`).
WARN: Skip abi_stable::TAG_ARR_2 - (not `pub`).
WARN: Skip abi_stable::TAG_MAP_EMPTY - (not `pub`).
WARN: Skip abi_stable::TAG_MAP_0A - (not `pub`).
WARN: Skip abi_stable::TAG_MAP_0B - (not `pub`).
WARN: Skip abi_stable::TAG_MAP_0E - (not `pub`).
WARN: Skip abi_stable::TAG_MAP_0F - (not `pub`).
WARN: Skip abi_stable::TAG_MAP_0G - (not `pub`).
WARN: Skip abi_stable::TAG_MAP_1A - (not `pub`).
WARN: Skip abi_stable::TAG_MAP_1B - (not `pub`).
WARN: Skip abi_stable::TAG_MAP_2A - (not `pub`).
WARN: Skip abi_stable::TAG_MAP_2B - (not `pub`).
WARN: Skip abi_stable::TAG_BOOLS - (not `pub`).
WARN: Skip abi_stable::TAG_UINTS - (not `pub`).
WARN: Skip abi_stable::TAG_INTS - (not `pub`).
WARN: Skip abi_stable::TAG_STRS - (not `pub`).
WARN: Skip abi_stable::EMPTY - (Unsupported path expression. [PathSegment { ident: Ident(CompTLFields), arguments: None }, Colon2, PathSegment { ident: Ident(EMPTY), arguments: None }])
WARN: Skip abi_stable::VARIANT_INDEX - (not `pub`).
WARN: Skip abi_stable::VARIANT_INDEX - (not `no_mangle`).
WARN: Skip abi_stable::NEW - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(TLNonExhaustive), arguments: None }, Colon2, PathSegment { ident: Ident(new), arguments: AngleBracketed(AngleBracketedGenericArguments { colon2_token: Some(Colon2), lt_token: Lt, args: [Type(Path(TypePath { qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(T), arguments: None }] } }))], gt_token: Gt }) }] } }), paren_token: Paren, args: [] }))
WARN: Skip abi_stable::EMPTY - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(Self), arguments: None }, Colon2, PathSegment { ident: Ident(from_fields), arguments: None }] } }), paren_token: Paren, args: [Macro(ExprMacro { attrs: [], mac: Macro { path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(rslice), arguments: None }] }, bang_token: Bang, delimiter: Bracket(Bracket), tokens: TokenStream [] } })] }))
WARN: Skip abi_stable::PARAM_INDEX - (not `pub`).
WARN: Skip abi_stable::PARAM_INDEX - (not `no_mangle`).
WARN: Skip abi_stable::EMPTY - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(LifetimeArrayOrSlice), arguments: None }, Colon2, PathSegment { ident: Ident(Array), arguments: None }] } }), paren_token: Paren, args: [Struct(ExprStruct { attrs: [], path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(ArrayLen), arguments: None }] }, brace_token: Brace, fields: [FieldValue { attrs: [], member: Named(Ident(len)), colon_token: Some(Colon), expr: Lit(ExprLit { attrs: [], lit: Int(LitInt { token: 0 }) }) }, Comma, FieldValue { attrs: [], member: Named(Ident(array)), colon_token: Some(Colon), expr: Array(ExprArray { attrs: [], bracket_token: Bracket, elems: [Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(LifetimeIndexPair), arguments: None }, Colon2, PathSegment { ident: Ident(NONE), arguments: None }] } }), Comma, Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(LifetimeIndexPair), arguments: None }, Colon2, PathSegment { ident: Ident(NONE), arguments: None }] } }), Comma, Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(LifetimeIndexPair), arguments: None }, Colon2, PathSegment { ident: Ident(NONE), arguments: None }] } })] }) }], dot2_token: None, rest: None })] }))
WARN: Skip abi_stable::NO_PATH - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(ModPath), arguments: None }] } }), paren_token: Paren, args: [Macro(ExprMacro { attrs: [], mac: Macro { path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(nul_str), arguments: None }] }, bang_token: Bang, delimiter: Paren(Paren), tokens: TokenStream [Literal { lit: "<no path>" }] } })] }))
WARN: Skip abi_stable::PRELUDE - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(ModPath), arguments: None }] } }), paren_token: Paren, args: [Macro(ExprMacro { attrs: [], mac: Macro { path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(nul_str), arguments: None }] }, bang_token: Bang, delimiter: Paren(Paren), tokens: TokenStream [Literal { lit: "<prelude>" }] } })] }))
WARN: Skipping abi_stable::destructor_arc - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::clone_arc - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::get_mut_arc - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::try_unwrap_arc - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::strong_count_arc - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::weak_count_arc - (not `pub` but is `extern "C"`)
WARN: Skip abi_stable::DEFAULT_VTABLE - (not `pub`).
WARN: Skipping abi_stable::destroy_box - (not `pub` but is `extern "C"`)
WARN: Skip abi_stable::DEFAULT_VTABLE - (not `pub`).
WARN: Skip abi_stable::VTABLE_VAL - (not `pub`).
WARN: Skip abi_stable::VTABLE_REF - (not `pub`).
WARN: Skip abi_stable::VTABLE_REF - (not `pub`).
WARN: Skipping abi_stable::is_equal - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::hash - (not `pub` but is `extern "C"`)
WARN: Skip abi_stable::_EMPTY_SLICE - (not `pub`).
WARN: Skipping abi_stable::as_debug_display - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::not_as_debug_display - (not `pub` but is `extern "C"`)
WARN: Skip abi_stable::VALUE - (not `pub`).
WARN: Skip abi_stable::WM_DEBUG_DISPLAY - (not `pub`).
WARN: Skip abi_stable::VALUE - (not `pub`).
WARN: Skip abi_stable::EMPTY - (Unsupported path expression. [PathSegment { ident: Ident(RSlice), arguments: None }, Colon2, PathSegment { ident: Ident(EMPTY), arguments: None }])
WARN: Skip abi_stable::NEW - (not `pub`).
WARN: Skipping abi_stable::new_utypeid - (not `no_mangle`, and has no `export_name` attribute)
WARN: Skipping abi_stable::some_utypeid - (not `no_mangle`, and has no `export_name` attribute)
WARN: Skipping abi_stable::no_utypeid - (not `no_mangle`, and has no `export_name` attribute)
WARN: Skip abi_stable::MAX_TYPE_ID_SIZE - (not `pub`).
WARN: Skipping abi_stable::destructor_vec - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::grow_capacity_to_vec - (not `pub` but is `extern "C"`)
WARN: Skipping abi_stable::shrink_to_fit_vec - (not `pub` but is `extern "C"`)
WARN: Skip abi_stable::DEFAULT_VTABLE - (not `pub`).
WARN: Skip abi_stable::NEW - (not `pub`).
WARN: Skip abi_stable::LOCK - (not `pub`).
WARN: Skip abi_stable::N_100 - (not `pub`).
WARN: Skip abi_stable::N_100 - (not `no_mangle`).
WARN: Skip abi_stable::N_277 - (not `pub`).
WARN: Skip abi_stable::N_277 - (not `no_mangle`).
WARN: Skip abi_stable::EMPTY - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(ref_as_nonnull), arguments: None }] } }), paren_token: Paren, args: [Reference(ExprReference { attrs: [], and_token: And, raw: Reserved, mutability: None, expr: Lit(ExprLit { attrs: [], lit: Int(LitInt { token: 0 }) }) })] }))
WARN: Skipping abi_stable::destroy - (not `pub` but is `extern "C"`)
WARN: Skip abi_stable::UID - (not `pub`).
WARN: Skip abi_stable::UID - (not `pub`).
WARN: Skip abi_stable::IMPL - (not `pub`).
WARN: Skip abi_stable::IMPL - (not `pub`).
WARN: Skip abi_stable::IMPL - (not `pub`).
WARN: Skip abi_stable::IMPL - (not `pub`).
WARN: Skip abi_stable::NEW - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(Implemented), arguments: None }] } }), paren_token: Paren, args: [Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(NonOwningPhantom), arguments: None }, Colon2, PathSegment { ident: Ident(NEW), arguments: None }] } })] }))
WARN: Skip abi_stable::VALUE - (not `pub`).
WARN: Skip abi_stable::NEW - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(Unimplemented), arguments: None }] } }), paren_token: Paren, args: [Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(NonOwningPhantom), arguments: None }, Colon2, PathSegment { ident: Ident(NEW), arguments: None }] } })] }))
WARN: Skip abi_stable::VALUE - (not `pub`).
WARN: Skip abi_stable::ROBJECT_VTABLE - (not `pub`).
WARN: Skip abi_stable::VTABLE_VAL - (not `pub`).
WARN: Skip abi_stable::TMP_VTABLE - (not `pub`).
WARN: Skip abi_stable::CONST - (Unsupported expression. Call(ExprCall { attrs: [], func: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(Trait_CTO), arguments: None }, Colon2, PathSegment { ident: Ident(from_const), arguments: None }] } }), paren_token: Paren, args: [Reference(ExprReference { attrs: [], and_token: And, raw: Reserved, mutability: None, expr: Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(Self), arguments: None }, Colon2, PathSegment { ident: Ident(NONE), arguments: None }] } }) }), Comma, Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(TU_Opaque), arguments: None }] } }), Comma, Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(Trait_MV), arguments: None }, Colon2, PathSegment { ident: Ident(VTABLE), arguments: None }] } }), Comma] }))
WARN: Skip abi_stable::CONST_A - (not `pub`).
WARN: Skip abi_stable::GLOBALS - (not `pub`).
WARN: Skip abi_stable::GLOBALS - (not `no_mangle`).
WARN: Skipping abi_stable::initialize_globals_with - (not `no_mangle`, and has no `export_name` attribute)
thread 'main' panicked at 'RResult has 2 params but is being instantiated with 1 values', src/bindgen/ir/enumeration.rs:596:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

But it fails. This is probably because of this warning in the official docs:

NOTE: A major limitation of cbindgen is that it does not understand Rust's module system or namespacing. This means that if cbindgen sees that it needs the definition for MyType and there exists two things in your project with the type name MyType, it won't know what to do. Currently, cbindgen's behaviour is unspecified if this happens. However this may be ok if they have different cfgs.

Are there any plans on generating C bindings? Is it feasible/of interest for this library?

No documentation for the `MapKey` and `MapQuery` types

I have been banging my head against the wall trying to make #83 work, and I have finally concluded that MapKey/MapQuery are at fault. I have been trying to understand it and I will eventually do, but it would have been a much nicer experience if they were documented in the first place. Currently, the only comment is this, for MapQuery, but I personally find it a bit lacking if you aren't familiar with the code:

/// A trait object used in method that access map entries without replacing them.

After reading it, I still have a few more questions after reading it: why the NotCopyNotClone marker? Why both MapKey and MapQuery? Why is this needed? Why is as_mapkey unsafe if we know that self is never going to be null? Shouldn't the MapQuery be Pinned?

The alternative is to remove them altogether, since they just seem to be a hack, though not sure if that would be possible. Any ideas regarding that? I wouldn't like to have someone go through this again.

It would also be nice to have some tests, like this one:

#[test]
fn map_key() {
    let test_key = "abc";
    let builder = DefaultHashBuilder::new();

    let query = MapQuery::<'_, &'static str>::new(&test_key);
    let mut hasher = builder.build_hasher();
    query.hash(&mut hasher);
    let query_hash1 = hasher.finish();

    let map_query = unsafe { &query.as_mapkey() };
    let mut hasher = builder.build_hasher();
    map_query.hash(&mut hasher);
    let query_hash2 = hasher.finish();

    assert_eq!(query_hash1, query_hash2);

    let map_value = MapKey::Value(test_key);
    let mut hasher = builder.build_hasher();
    map_value.hash(&mut hasher);
    let value_hash = hasher.finish();

    assert_eq!(value_hash, query_hash2);
}

Compilation Error for README Example in 3 Separate Crates

I'm a newcomer to this crate. I noticed that the documentation mentioned that the interface and implementation generally reside in separate crates, so I was trying to get the example working in that fashion. I commented out the single-crate version of load_root_module_in_directory and uncommented the 3-crate version. However, cargo build -p implementation then results in:

error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
   --> implementation/src/lib.rs:112:1
    |
112 | impl<T> Appender for RVec<T> {
    | ^^^^^^^^^^^^^^^^^^^^^-------
    | |                    |
    | |                    `RVec` is not defined in the current crate
    | impl doesn't use only types from inside the current crate
    |
    = note: define and implement a trait or new type instead

What would be the recommended solution? I don't have enough knowledge of abi_stable to answer that myself.

My example repository, if helpful: https://github.com/Neightro/abi_stable_readme_example

Is it possible for RBox<T> to allow T: ?Sized ?

Wasn't sure if there was a specific reason why RBox<T> doesn't loosen the Sized constraint on T. If there is a reason I'd be interested to understand it, and I think it'd be good to include it in the documentation.

Question about use case with DLL unloading

These are some usecases for this library:

  • Creating a plugin system (without support for unloading).

Does this mean using this crate when my plugins should support unloading would be unsafe?

In my use case I'm using this crate to auto-reload recompiled plugins:
https://crates.io/crates/dynamic_reload

My DLL entry point returns a Plugin trait object that the host takes ownership of.
And yes, I drop this trait object before unloading the DLL.
My question is, can I still use this crate?

Do I even need to, when host and plugin are always compiled with the same nightly?
(Does it make a difference if the DLL is a dylib or cdylib regarding ABI stability guarantee?)

Everything seems to work fine when using cdylib and compiling with the same nightly, even without marshalling my types across the DLL boundary, but people told me the ABI could change even between different invocations of the same rustc.

Reduce the size of type layout constants

I am currently working on making the size of type layout constants smaller for the 0.7 release.
I'll commit the work on this next week in the 0.7 branch(which is for developing the 0.7 version before releasing it).

Here are some things I am going to do to make the type layout constants smaller:

  • Storing the pointer for slices separate from lengths,storing the pointer to the first element for the slices in a struct together,then the length of the slices as u16s.
  • Using manually-implemented bitfields.
  • Reordering fields based on their size.
  • Storing strings that aren't used for checking types as 0-terminated strings.
  • Storing the data in type layout constants that doesn't change with generic parameters separately from the parts that might.

Fn-types

I'm currently missing a stable_abi alternative for Fn, FnMut and FnOnce. I'm planning to implement those in the following style:

#[repr(C)]
#[derive(StableAbi)]
pub struct RBoxFnOnce<TParam, TResult> {
    caller: extern "C" fn(usize, TParam) -> TResult,
    remover: extern "C" fn(usize),
    inner: usize,
}

impl<T, TParam, TResult> From<T> for RBoxFnOnce<TParam, TResult> where T: FnOnce(TParam) ->TResult {
    fn from(inner: T) -> Self {
        let box_inner = Box::new(inner);
        let inner : usize = Box::into_raw(box_inner) as usize;

        extern "C" fn caller<T, TParam, TResult>(that: usize, param: TParam) -> TResult where T: FnOnce(TParam) -> TResult {
            let function = unsafe { Box::from_raw(that as *mut T) };
            (function)(param)
        }
        extern "C" fn dropper<T, TParam, TResult>(that: usize) where T: FnOnce(TParam) -> TResult {
            drop(unsafe { Box::from_raw(that as *mut T) });
        }
        Self {
            caller: caller::<T, TParam, TResult>,
            remover: dropper::<T, TParam, TResult>,
            inner
        }
    }
}

impl<TParam, TResult> Drop for RBoxFnOnce<TParam, TResult> {
    fn drop(&mut self) {
        if self.inner != 0 {
            (self.remover)(self.inner);
        }
    }
}
impl<TParam, TResult> RBoxFnOnce<TParam, TResult> {
    fn call(mut self, p: TParam) -> TResult {
        let inner = self.inner;
        self.inner = 0;
        (self.caller)(inner, p)
    }
}

Usage looks like:

fn api(f: impl Into<RBoxFnOnce<usize, usize>>) {
    assert_eq!(5, f.into().call(1));
}

#[test]
fn test () {
    let ctx = "Test".to_string();
    api(move |x| {
        let a = ctx;
        x + a.len()
    })
}

I'm not very experienced, but IMO this shouldn't have undefined behavior. If you are interested to integrate such functionality into stable_abi, I'm happy to fork your repo and push everything upstream eventually. Otherwise, I'll just create my own repo. Please let me know about your preferences.

Plugins depending on other plugins

At first sight this crate does many things I've tried to accomplish in the past 2 years in my free time, so thank you for that.

Before I dig in further, I wanted to ask if, in a plugin system, any if the plugins can get as dependency any other plugins?

Of course:

  • I would have to ensure in my application that there are no dependency cycles in the graph
  • I would need to construct my plugins in two stages, one in which they can advertise "their handle" (akin to TypeId) and a list of handles that they depend on, and the second stage in which I sort topologically the dependency graph and actually start each plugin with all the dependencies they need

If not currently possible, do you see this as a possible feature which can be planned in? Would it be before 1.0.0 or after that?

support "C-unwind" ABI

Is it possible to support "C-unwind" ABI? Is there a temporary workaround to change the generated extern "C" to extern "C-unwind"?

Separate the FFI-safe types from the rest of the crate

Hello, first of all, thanks for this amazing crate.

In my project, I find your #[repr(C)] equivalents of common types from std and such (RVec, RString, etc) very useful, however - everything else on this crate - not so much.

I was wondering if it would be possible to separate the abi_stable::std_types module to a separate crate, that would just provide #[repr(C)] types and a simple numerical ABI_VERSION constant. That would make things much simpler for my project (and others, my case is definitely not the only one), help compilation times and so on. Making modular libraries is always a good practice.

Unloading libraries and releasing file locks

I've been developing something using abi_stable for a while now, and the biggest pain point is that, because it ideally stays open at all times, it's not possible for me to swap out the dlls as I develop them without fully shutting down and re-opening my application. Is there any way to fully unload and release the lock on the files? I'm dropping the instances and they're getting cleaned up, but the files stay open.

How to design a plugin that may requires one trait from interface crate, and provides another in interface crate?

Recently I am developing for a massive embedded chip debugger software. I uses abi_stable to design its plugin system, because this software may allow users to install plugins for backends, interface adapters and chip targets. I could design one interface crate, but here are still two (or maybe three) types of plugin crates that I need to implement:

  1. Service provider plugins. They should rely on no interfaces (actually backed with operating systems or other native code), and provides services (maybe traits) in interface crate;
  2. Adapter plugins. They may rely on one or more interfaces, providing one or more interfaces at the same time. That could represent a protocol adapter, a hub or a switch as hardware;
  3. Consumer plugins. They could rely on interfaces, but provides nothing. That could be a debug logger or devices for measuring.

To make things clear I have an example. Users may plug a JTAG dongle onto USB slot, then connect target MCU board with this dongle. So here I need three plugins. First one wraps WinUSB or other operating system specific functions to provide universal USB structures in interface crate. Second one wraps dongle protocol support that requires USB traits and provides JTAG traits. Third one requires JTAG and provides a universal chip target flash trait. Finally the application may enumerate all flash traits using all three plugins and pick one flash trait to perform the flash write command.

Here I need to implement all three plugins. The first could be easy as it could be implemented as a trait object that could provide to interface crate, as examples in abi_stable project have done. But the second and third ones are somehow tricky (I haven't find a way) to write, because they not only provides interfaces like usual plugins, but also requires one interface from the crate thus somehow performs just like an application.

Is there existing solutions to my problem? Or how should I design a system that allows plugin to provide interface implementations as well as requires some interfaces? Please provide with useful suggestions or example code, thanks!


This is a help-wanted issue. I don't know if it's proper to post it here; if not, please let me know. Thanks!

Type `char` does not implement `StableAbi`

When trying to use char as an FFI type, the error below is thrown. According to the documentation, a char is always four bytes in size, so this should not be hard to support.

the trait bound `char: abi_stable::StableAbi` is not satisfied
the following other types implement trait `abi_stable::StableAbi`:
  &'a T
  &'a mut T
  ()
  *const T
  *mut T
  [T; N]
  abi_stable::DynTrait<'borr, P, I, EV>
  abi_stable::RMut<'a, T>
and 315 others
required for `[char; 2]` to implement `abi_stable::StableAbi`
2 redundant requirements hidden
required for `abi_stable::std_types::ROption<abi_stable::std_types::RVec<[char; 2]>>` to implement `abi_stable::StableAbi`

Mark ref_as_nonnull function as unsafe

Hello, I found a soundness issue in this crate.

pub const fn ref_as_nonnull<T: ?Sized>(reference: &T) -> NonNull<T> {
unsafe { NonNull::new_unchecked(reference as *const T as *mut T) }
}

https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.new_unchecked
The unsafe method called needs to ensure that the parameter must be non-null, and the developer who calls the ref_as_nonnull function may not notice this safety requirement.
Marking them unsafe also means that callers must make sure they know what they're doing.

Loading multiple implementation of an interface

The glossary section in docs.rs index mentions:

user crate:A crate that depends on an interface crate and loads 1 or more implementation crates for it.

But calling RootModule::load_from_file twice with different implementation DLL files returns a reference to the implementation from the first DLL on both occurrences.

Delving into its source code, it seems to keep a single static reference per interface type, which is initialized on the first call to RootModule::load_from_file and all subsequent calls to RootModule::load_from_file returns a copy of it irrespective of the parameter it has been called with.

Now, how multiple implementation DLLs of some interface can be loaded? If it needs some change in the abi_stable crate, I would be happy to help.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.