mozilla / uniffi-rs Goto Github PK
View Code? Open in Web Editor NEWa multi-language bindings generator for rust
Home Page: https://mozilla.github.io/uniffi-rs/
License: Mozilla Public License 2.0
a multi-language bindings generator for rust
Home Page: https://mozilla.github.io/uniffi-rs/
License: Mozilla Public License 2.0
Panics in the rust code are not currently handled very well, and I suspect would actually trigger undefined behaviour by propagating across the FFI boundary. We should use the support functions offered by ffi-support to ensure safe panic handling in all cases.
The most basic thing that could work:
ExternError
out parametercall_with_output
.Object methods could instead rely on the call
helpers of the HandleMap
for the same effect, but I think it would be worth our while to catch and handle panics in argument conversion or other operations that might occur before we call into the HandleMap
at all.
┆Issue is synchronized with this Jira Task
Investigate how our minizord mashes up with Android Components—given that the components are standalone, but we want the Glean and Nimbus wrappers to use the same minizord
┆Issue is synchronized with this Jira Task
Prototype a way to add uniffi to https://github.com/a-s-dev/glean/pull/1/files/28bbd0e637a27777ed35b1d146e605c6b62194d9?short_path=35660eb#diff-35660eb478d9194651365436ecf6a68a prototype and generate the ffi for Kotlin
┆Issue is synchronized with this Jira Task
The Python bindings already define __del__
destructors for classes, but Kotlin and Swift don’t yet. We’ll want to make sure we wire these up and call them correctly, to avoid leaks and double-frees.
┆Issue is synchronized with this Jira Task
There are some bucketing specs at https://docs.google.com/document/d/1WAForAUIchVPaiZFCJO3hNQHY_7KZAjddfscTM_Lx0Y/edit#heading=h.ilipj4uaks21
Some of it is already in the prototype, we need to add the missing bits, such as namespacing
and add testing
┆Issue is synchronized with this Jira Task
From #2
I'd like to be able to turn the existing example.py and example.kts files into actual tests with assertions that can be executed to make sure the generated bindings are working as expected. So far I've just been running them by hand and eyeballing the output, but that's clearly not going to scale.
The way uniffi is currently set up, optimizes for a very specific use-case: you're building a crate and you're going to publish it as a rust component, so you want uniffi integrated at the top level of your build process (cargo build
produces the .so
, cargo run -- generate
produces the foreign-language bindings, etc).
From some thoughtful feedback from @tarikeshaq over in https://github.com/rfk/uniffi-rs/issues/24#issuecomment-661608571, it's clear that the first set of potential real-life consumers won't be shaped like that. They're more likely to want to tentatively integrate uniffi into the build process of an existing project, and it's not obvious how to do that based on what we have right now.
A strawfox proposal, broadly inspired by how we use protobufs in app-services:
uniffi-bindgen
tool that can be used in a standalone fashion, for integration with other build setups. We actually already have the beginnings of this, but it's hidden away in implementation details.uniffi-bindgen scaffolding path/to/api.idl
that can read an IDL file and spit out the rust code that flattens it into a C-style FFI. Rather than writing a bunch of pub extern "C"
functions by hand, consumers could use this tool to generate them automatically from the IDL file and then include!()
them into their rust code (or perhaps import them as a sub-module?).uniffi-bindgen generate --language=<language> path/to/api.idl
that can read an IDL file and spit out the appropriate foreign-language bindings to consume the C-style FFI from above. Rather than writing Kotlin, Swift etc code by hand, consumers could use this tool to generate it automatically from the IDL file, and then incorporate the generated files into their package build.That's going to feel a bit clunky as a dev experience, in much the same way that working with protobuf files feels a bit clunky for us in app-services (like the CI job whose only purpose is to check that you didn't forget to generate the bindings). But from recent conversations, I think it could set us up to deliver early value quicker, without having to solve a bunch of more general tooling challenges up-front.
Most of the codegen pieces for this already exist, but need to be exposed for easy use in this new way from the command-line.
Thoughts? /cc @eoger @jhugman @linacambridge @tarikeshaq
┆Issue is synchronized with this Jira Task
This currently does not work:
namespace bobo {
double do_something(MyType? arg);
}}
Error is
thread 'main' has overflowed its stack
fatal runtime error: stack overflow
[1] 78220 abort cargo run -- generate
It is not currently possible to pass objects as arguments to functions or methods, apart from the special-case handling of the implicit first argument in a method call.
In theory this should be easy right? You accept the u64
handle as an argument, look up the object in the appropriate handle-map, and you're off to the races!
There are significant complexities in practice. I don't think we need this functionality with any urgency but I wanted to put a bug on file for why this is harder than it might seem. Some thoughts below, please comment with others if you have them.
If the object argument needs to be mutable, then we can't just grab the object out of the handle-map, we have to use a closure that manages locking for exclusive access. If we have several object arguments, we would need to codegen a series of nested closures, which could get messy fast.
Mutable object arguments are also a deadlock hazard. Imagine a function call that takes two object arguments, like modify(obj1, obj2)
, and a concurrent call to modify(obj2, obj1)
. If we naively try to access each object argument in turn inside the generated FFI function, then the first call will lock obj1
, and second call will lock obj2
, and then they'll both deadlock waiting for the lock on their second argument. We might be able to mitigate that by locking object arguments in a consistent order, such as always trying to lock arguments with lower numeric handles first. But that'll make the codegen even messier.
┆Issue is synchronized with this Jira Task
All bindings define some internal helper methods on the records and classes they generate—things like lift
, lower
, liftFrom
, lowerInto
, lowersToSize
, toFFIValue
, and fromFFIValue
—as well as internal types like RustBufferStream
. What happens if a type declares a method in its IDL with the same name as one of those internal helpers?
This is broadly related to #2, although more specialized.
Approach one
RustBufferStream
would be blocked only in Python, liftFrom
, lowerInto
, and lowersIntoSize
only in Kotlin, and toFFIValue
and fromFFIValue
only in Swift.A benefit of language-specific lists would also help us block accidental use of reserved words. For example, def
is reserved in Python, but none of the others; trait
can’t be an argument name in Rust, but can be used freely in others; func
is reserved only in Swift, fun
only in Kotlin, and so on. Of course, we could also block these globally—so you couldn’t use def
, func
, or trait
as an argument name in any language.
Drawbacks: authors have to think of new names themselves, and it doesn’t handle extensions and subclasses (do we care?).
Approach two. Try to uniquify internal helper names. This would be more helpful for authors, but feels too magical, and has lots of corner cases and hacks. The idea is, we’d have a list of all user-defined method names, and generate a unique one for the internal helper only if there’s a collision. It keeps the generated code clean in most cases, since we’d only mangle names if we see a collision.
There are drawbacks to this, though. First, for methods, we have to rename the whole method globally, even if there’s only one collision. As soon as a type defines, say, a lower
method, we have to call our internal one lower0
everywhere. It means we have to keep track of more state, making the parser more complicated. Also, each language has its own notion of what’s a collision and what’s not—in Swift, labels and return types are part of the name, so it’s perfectly OK to have lower(into writer: Writer)
, lower(b: Int)
, and lower() -> Foo
; in other languages, it’s not. And it also doesn’t handle extensions and subclasses—what happens if you subclass or extend a generated type, and define a reserved name on it?
Approach three. Unconditionally append a random, short ID to internal symbols. Essentially, this means doing our own name mangling—things like Lowerable_AZBYCX1234
. This makes the generated code uglier and harder to debug, and does it for all bindings, even if they don’t define colliding names. It also introduces churn, because regenerating the bindings would write a new ID (though we can make the scheme predictable—again, borrowing from how name mangling works in other languages). And it makes collisions virtually impossible.
Approach 3.1: prefix or suffix internal stuff (and reserved words!) with _
. Also easy, and probably good enough!
I feel like approach one is the easiest and least magical option, but let’s discuss, and mention other approaches we think of!
┆Issue is synchronized with this Jira Task
┆Issue Number: UNIFFI-2
uniffi-rs/uniffi/src/bindings/python/templates/RustBufferHelper.py
Lines 43 to 44 in 3c36c7b
This looks like this corresponds to a put_u32
on the Rust size, looking at the Python docs it looks like we need to use I
instead.
┆Issue is synchronized with this Jira Task
I am seeing bugs around Optional lift/lower that I'm not sure I know how to fix
┆Issue is synchronized with this Jira Task
Mainly as an exercise to get familiar with uniffi! 😊
User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0
Actual results:
1595991934794 Sync.LogManager DEBUG Flushing file log
1595991934808 Sync.LogManager DEBUG Log cleanup threshold time: 1595127934808
1595991934826 Sync.LogManager DEBUG Done deleting files.
1595991939120 Sync.ErrorHandler DEBUG Beginning user-triggered sync.
1595991939122 Sync.Service DEBUG User-Agent: Firefox/59.0.2 (Windows NT 10.0; Win64; x64) FxSync/1.61.0.20180323154952.desktop
1595991939122 Sync.Service INFO Starting sync at 2020-07-29 09:05:39 in browser session 4IGBiemCVu6c
1595991939122 Sync.SyncScheduler DEBUG Clearing sync triggers and the global score.
1595991939126 Sync.Status INFO Resetting Status.
1595991939126 Sync.Status DEBUG Status.service: error.sync.failed => success.status_ok
1595991939126 Sync.Status DEBUG Status.sync: success.sync => error.login.reason.network
1595991939126 Sync.Status DEBUG Status.service: success.status_ok => error.sync.failed
1595991939128 Sync.ErrorHandler ERROR Sync encountered an error: Error: Can't sync: Network is offline (resource://services-sync/stages/enginesync.js:50:13) JS Stack trace: [email protected]:50:13 < [email protected]:1106:13 < [email protected]:181:27 < [email protected]:137:22 < [email protected]:1099:12 < sync/<@service.js:1091:13 < [email protected]:107:22 < [email protected]:1080:12
1595991939128 Sync.SyncScheduler DEBUG Sync error count has exceeded 3; enforcing backoff.
1595991939128 Sync.SyncScheduler DEBUG Starting client-initiated backoff. Next sync in 7633152 ms.
1595991939128 Sync.SyncScheduler DEBUG Next sync in 7633152 ms. (why=client-backoff-schedule)
1595991939134 Sync.Service DEBUG Exception calling anonymous function: Error: Can't sync: Network is offline (resource://services-sync/stages/enginesync.js:50:13) JS Stack trace: [email protected]:50:13 < [email protected]:1106:13 < [email protected]:181:27 < [email protected]:137:22 < [email protected]:1099:12 < sync/<@service.js:1091:13 < [email protected]:107:22 < [email protected]:1080:12
1595991939136 Sync.ErrorHandler DEBUG Addons installed: 0
🪲 Issue is synchronized with Bugzilla Bug 1655894
┆Issue is synchronized with this Jira Task
In the fxa-client crate the FirefoxAccount
can be instanced in two ways: either by its regular constructor or by supplying a JSON string representing a previous state. IIUC we don't have support for an alternative interface constructor right now..
┆Issue is synchronized with this Jira Task
Build
Prod [Train 1.181.2]
Affected platforms
Windows 10
iOS 13.6
Steps to reproduce
Expected results
Both Android and iOS are mentioned as being able to scan the pairing code.
Actual Results
Only Android is specified in the following paragraph: “2. Then sign in to Sync, or on Android scan the pairing code from inside the Sync settings.”
┆Issue is synchronized with this Jira Task
The example code so far only really exercises support for numbers. In practice we have a lot of code that uses strings, so we need to be able to deal with those conveniently and safely.
Adding support for strings would be a good opportunity for someone new to this codebase to get involved. They would need to:
cargo build
your example component, and confirm that it doesn't compile. If it does compile despite not having support for strings, that's a separate bug...uniffi::support
.
Lowerable
by writing out a fixed-size length field, followed by the body of the string.Liftable
by doing the reverse, reading the fixed-size length followed by the string data.ViaFfi
using the ffi_support::FfiStr
helper, which is what we use for strings in our hand-written rust component today.uniffi:scaffolding
]. There's some placeholder stuff in there using &str
and FfiStr<>
but it'll probably need adjusting.
cargo build
your example component and have it work successfully.FfiStr
above, you might find that passing strings are arguments just works, because the native-code-binding layers of each language know how to pass a string object as a const char*
in their FFI layers.There are quite a few places where we're doing the same thing, but with minor differences in the header or footer.
e.g.
We should investigate ways our templates could be split up and parameterized so working with templates easier for language experts and more readable.
stucts
and rendering templates in place.path
sub-attribute of the template
attribute.include
directive. e.g. {% include "hotmess.txt" %}
This is likely a starting point / meta for smaller bugs rather than a specific piece all on its own.
We have some logic in the sync ping to force submission of the ping when we notice an "idchange" (aka a user change or a change in sync storage node type), but it doesn't look like this is hooked up to submit when the user logs out. Thus we might have information about some number of completed syncs queued up in the sync ping, but never submit it because the user has since signed out.
Let's add some logic to the existing onAccountLogout
handler for the sync ping, to flush any pending telemetry on logout.
🪲 Issue is synchronized with Bugzilla Bug 1655899
┆Issue is synchronized with this Jira Task
This is based on the discussion in https://github.com/rfk/uniffi-rs/pull/22#discussion_r456967989.
This would entail the following:
ViaFfi
trait in https://github.com/rfk/uniffi-rs/blob/e35bbac8880b61de1ef9a73e736d4f6b7933244e/uniffi/src/support/mod.rs#L105-L122fn into_ffi_value(self) -> Self::Value;
functionfn try_from_ffi_value(v: Self::Value) -> Result<Self>;
functionViaFfi
into two separate impls, one for IntoFfi
and one for TryFromFfi
, you will notice that you only need to implement TryFromFfi for &str (And not IntoFfi
) and only need to implement IntoFfi
for String (And not TryFromFfi
) - Note: The string stuff only applies if #25 merges before you do thisI might have missed something, \cc @rfk I think this is a good-first-issue
kind of issue, so feel free to add any details 😄
┆Issue is synchronized with this Jira Task
I pushed this code in a separate repo in order to be able to iterate without landing it in application-services, and it's never been my intention for it to live here for a significant amount of time. Have we done enough experimenting here to make a decision about where it should live longer term? Some options that we should consider:
Not my preferred option, but I think we should be explicit that this remains on the table. If we've tried playing around with autogenerating FFI bindings and it seems like it's going to be too much complexity for too little reward, we should capture our learnings somewhere for posterity, and move on.
In its current form the code here is not ready for use in a "real" component. To meet that bar it would need, at a minimum: support for strings, basic error handling, and integration with the appservices megzording logic.
But if we think the remaining work is tractable enough and the potential for saving work is big enough, we could commit to trying this out on an upcoming component and move it over to the appservices repo for further iteration.
As above, but in a separate repo rather than as part of apps-services. We'd have to understand what we hope to gain from it being in a separate repo, to offset the extra workflow friction when trying to iterate on the tool and its consumers in two separate repos.
"We don't know yet" is a fine position to have, but if that is indeed where we are, I'd like to figure out a plan for coming to know at some point in the future :-)
This is an auto generated bridge that allows the rust component to work between mobile and desktop. Using auto generated uniffi so that we can write fewer boiler plates (reference: https://github.com/rfk/uniffi-rs#what))
┆Issue is synchronized with this Jira Epic
Sequences (or "lists" or "arrays" or "vectors" or whatever you like) are a pretty important data type that we don't currently have support for. Let's add them!
I think we can use the existing Optional
type as a good template. Broadly, we'll need to:
sequence<T>
for any type T
.uniffi/src/interface/types.rs
but it might need some tweaking.cargo build
the example and confirm that it doesn't work yet.Option<T>
type, it seems reasonable to me to always pass them as a bytebuffer.uniffi/src/support
by implementing the Liftable
and Lowerable
traits for Vec<T>
, and them implementing ViaFfi
for Vec<T>
by using them (similar to what's done for Option<T>
.uniffi/src/scaffolding
, again following the example of option types.Option<T>
as a guide.cargo test
to confirm that your updated example code works correctly with sequence types!┆Issue is synchronized with this Jira Task
We are in the process of implementing a new storage quota that will affect user collections.
On the client, we'd like to prevent users who have exceeded this quota from syncing. We should also log something that we can easily track for debugging purposes in the future.
See plan here related to this work.
🪲 Issue is synchronized with Bugzilla Bug 1655531
┆Issue is synchronized with this Jira Task
We currently have bindings for Kotlin and Python, with Swift in progress. It would be wonderful to generate them for Desktop, too. There are a couple of uniquely Desktop (mostly in the jeez-this-is-clunky sense 😅) things to think about, so let's use this issue to plan out how to do this.
Our current approach is to consume the component's Rust API, and hand-roll a Rust XPCOM wrapper around it, so that JS can call it. This was a quick way to ship our first components. Unfortunately it has a few downsides:
.jsm
wrapper because using the interface directly is so clunky.XPIDL does have several escape hatches. Methods can return Promise
s, instead of having to implement their own callback interfaces. jsval
and webidl
types are much easier to use from JS (and C++!) An XPIDL interface that makes heavy use of these can be almost as ergonomic as a WebIDL one.
Unfortunately, Rust XPCOM can't do any of those.
nostdcall
, notxpcom
(these use different calling conventions), or noscript
method, even if it supports that method's types.jsval
, webidl
, or native
type. The first two require Rust SpiderMonkey bindings, and the last is C++-only.Although there are helper crates in the tree to make it easier to use Rust XPCOM, it's not as mature or well-supported as C++ or JS yet 😭
So, what else can we use to talk to Rust from JS? Chrome WebIDL, js-ctypes
...and XPCOM interfaces implemented in C++. Let's look at that last one a bit closer. Since we're generating code, anyway, why not target C++ instead of Rust?
What if we made a backend that spits out an XPIDL interface and a C++ implementation? It could be async-by-default, using the C++ TaskQueue
class, the same one we used for storage.sync
and FxA in Rust. It can return promises, and handle threading for us automatically (ooh, threading is a whole other discussion...let's use another issue for that). It could lower jsval
s to RustBuffer
s, pass them over the FFI on a background thread, lift the returned value into another jsval
, and resolve a promise with it—going through the same flow for calling our Rust component as other FFIs.
What are the other alternatives?
chrome-webidl
. Used mostly for hot code. We're discouraged from using it heavily, since there is a binary size cost ("A WebIDL method binding can easily cost a kilobyte or more, depending on the number and types of the arguments."), and lots of security semantics that don't really apply for chrome code. Much better integration with JS; easy-ish to call from C++, depending on what you're doing.js-ctypes
. Lotsa sharp edges, but can be used from JS directly, no need for a C++ wrapper. Can use symbols from libxul. Can also be used from a ChromeWorker
(on a background thread), communicating with the main thread using message passing. Can't be used from existing Firefox C++ components—might be a concern when we Oxidize other components, but perfect for JS-only ones.┆Issue is synchronized with this Jira Task
Create a simple crate structure inside of the Glean repo for experiments
┆Issue is synchronized with this Jira Task
I want to be able to compile the following
boolean return_true();
Currently I'm getting the error:
87 | <u8 as uniffi::support::ViaFfi>::into_ffi_value(_retval)
| ^^^^^^^ expected `u8`, found `bool`
Related to https://jira.mozilla.com/projects/EXP/issues/EXP-32
The schemas has a filter expression that needs to be supported in some ways. There should be some prior art for this. Need to check with the Glean / Nimbus teams before we proceed with one.
┆Issue is synchronized with this Jira Task
┆Issue is synchronized with this Jira Epic
The way we run Swift examples now is hecka janky.
If you're using a generated library in an Xcode project, you only need the bridging header (am I using the right terminology for this? It's an "umbrella header" for the module map, but I think "bridging" means something very specific, and suspect this isn't that) and the .swift
source file for the component—it'll take care of the rest. But, we need to do some clever things to run the example manually.
First, we compile our component.swiftmodule
and libcomponent.dylib
with swiftc
, and link that with the Rust FFI library (libuniffi_component.dylib
). If we don't link with the FFI library, it'll complain it can't find any of the C FFI symbols when it goes to compile the Swift module. We also have to pass it a module map, which has the path to the "bridging header" declaring the FFI symbols. The libcomponent.dylib
is the weird part—why do we need that? Apparently, component.swiftmodule
module isn't enough; without libcomponent.dylib
, running import component
will work, but calling any of its functions will fail with an error that it can't find the Swift symbol.
Then, when we want to run an example script that imports the component, we call swift
(not swiftc
), and link the example script with the component.dylib
we emitted in step 1. We don't have to link the script with the FFI library, but we do have to pass the same module map again.
SPM does this automagically under the hood. The way I figured out these incantations was doing swift build -v
and swift run -v
, looking at the commands, and whittling down the arguments until it worked 😆
For us, though, we'll need a better way that doesn't rely on run_swift_script
hardcoding library names and module map paths. @rfk mentioned in https://github.com/rfk/uniffi-rs/pull/6#discussion_r446863815 that the component name gets passed down here, which we'll need as the base for the different library and module map paths.
Currently, our story is something like this: the Rust components expose synchronous APIs, and do blocking filesystem I/O and network consumers. Consumers wrap them in whatever async API makes sense for their needs—Kotlin Coroutines, Swift Dispatch Queues, Gecko Background Task Queues and so on.
There are several big advantages, the biggest one being keeping our components simple:
await
point.HandleMap
means we can guarantee our Rust calls will be serialized. It's easy to understand what's going on conceptually.On the flip side:
AsyncLoginsStorage
, whose reason for existence is rewrapping the logins component's API in coroutines.async
/await
world? Would we ever be able to migrate our components to use it? Is that a thing we want?We should break up the rust scaffolding templates in the same manner as #17.
Lead by Kirby and working with the Comms team, we're going to prepare a blog post to accompany the landing of AET in nightly, to help set expectations for anyone who sees a new telemetry ping and gets curious/suspicious/outraged. This is a placeholder issue to flag the fact that this work is taking place and consuming some of my bandwidth, we don't need to land anything in our repos in support of this.
┆Issue is synchronized with this Jira Task
We already have a lot of parts included in the prototype here: https://github.com/a-s-dev/glean/pull/1/files/28bbd0e637a27777ed35b1d146e605c6b62194d9?short_path=35660eb#diff-35660eb478d9194651365436ecf6a68a
We need to implement to scheduling and refresh the experiments from the server when needed.
From @mdroettboom on Slack, it sounds like a great idea .
┆Issue is synchronized with this Jira Task
Currently, every rust function exposed over the FFI is expected to take ownership of its arguments. This is most obvious in the existing "sprites" example, where the code for translate
has to be declared as:
fn translate(p: Point, v: Vector) -> Point
Which means that when the move_to
method of the Sprite
class calls it, it has to pass in a clone:
self.current_position = translate(self.current_position.clone(), direction)
Making this more egonomic could be a good opportunity for somone new to the codebase to get familiar with it. The challenge would be to update the sprites example so that the translate
function is declared as:
fn translate(p: &Point, v: &Vector) -> Point
And the .clone()
mentioned above can be removed.
In order to achieve this I think you would need to:
Argument
struct so that it's available when you're generating the code.Argument
struct that currently says "argument attributes are not yet supported", which corresponds to the extended attributes feature of WebIDL.translate
function in sprites.idl
, something like Point translate([ByRef] Point position, [ByRef] Vector direction)
.
attributes
member on the arguments that we get back from the WebIDL parser!Argument
strut, then use that flag during code-gen to know whether to pass by reference.┆Issue is synchronized with this Jira Task
Potentially right now Fenix testers would want to change the following parameters while testing nimbus:
[ConfigurationDetails]
Option,
Option,
Option
┆Issue is synchronized with this Jira Task
We have lots of TODO
s for adding error handling. A few things we’ll want to think about:
Result
return values? Following how Firefox does it, using a Throws
annotation on fallible methods? Do we want to have structured errors that can be inspected, or are error strings good enough?throws
keyword to indicate a function is fallible, and Kotlin and Python functions can throw exceptions. We will need to teach our code generation layer to reflect error results as exceptions.┆Issue is synchronized with this Jira Task
We should decide on the basics of:
The discussion is happening in this Google doc
┆Issue is synchronized with this Jira Task
I want to be able to compile the following code:
dictionary Point {
double x;
double y;
boolean visited;
};
Currently getting errors:
error[E0277]: the trait bound `bool: uniffi::support::Lowerable` is not satisfied
--> /Users/eoger/uniffi-rs/target/debug/build/uniffi-example-geometry-32b57fa3d176b525/out/geometry.uniffi.rs:38:9
|
38 | uniffi::support::Lowerable::lower_into(&self.visited, buf);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `uniffi::support::Lowerable` is not implemented for `bool`
|
::: /Users/eoger/uniffi-rs/uniffi/src/support/mod.rs:17:22
|
17 | fn lower_into<B: BufMut>(&self, buf: &mut B);
| ------ required by this bound in `uniffi::support::Lowerable::lower_into`
error[E0277]: the trait bound `u8: uniffi::support::Liftable` is not satisfied
--> /Users/eoger/uniffi-rs/target/debug/build/uniffi-example-geometry-32b57fa3d176b525/out/geometry.uniffi.rs:47:22
|
47 | visited: <u8 as uniffi::support::Liftable>::try_lift_from(buf)?,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `uniffi::support::Liftable` is not implemented for `u8`
|
::: /Users/eoger/uniffi-rs/uniffi/src/support/mod.rs:68:25
|
68 | fn try_lift_from<B: Buf>(buf: &mut B) -> Result<Self>;
| --- required by this bound in `uniffi::support::Liftable::try_lift_from`
error[E0308]: try expression alternatives have incompatible types
--> /Users/eoger/uniffi-rs/target/debug/build/uniffi-example-geometry-32b57fa3d176b525/out/geometry.uniffi.rs:47:22
|
47 | visited: <u8 as uniffi::support::Liftable>::try_lift_from(buf)?,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `u8`
┆Issue is synchronized with this Jira Task
Followup from discussion in #2
There are a number of examples where mangling of names to fit foreign naming conventions may cause collisions.
namespace {
fooBar();
foo_bar();
};
dictionary MyDict {
string fooBar;
string foo_bar;
};
interface MyObject {
void myMethod(string fooBar, string foo_bar);
};
enum MyEnum {
"fooBar",
"FOO_BAR",
};
enum FooBar {};
dictionary Foo_Bar {};
This is likely to be fixed in the same place as #10 . Bailing with a helpful error message will probably be the best we can hope for.
Thankfully, it appears we won't need to worry too hard about differing definitions of unique function signatures because rust only seems to take into account the function name.
There is a possibility of the user threading the needle here for two function with a name collision after normalization, but also a different arity.
e.g.
namespace {
void foo();
void Foo(uint32 i);
}
I think it would be better if we disallowed this rather than introducing more and more sophisticated methods.
┆Issue is synchronized with this Jira Task
┆Issue Number: UNIFFI-3
In this prototype we have the following fields supported in AppContext
:
https://github.com/a-s-dev/glean/pull/1/files#diff-c7271f5c37709867ac4f79e6d85240ceR27
pub app_id: Option<String>,
pub app_version: Option<String>,
pub locale_language: Option<String>,
pub locale_country: Option<String>,
pub device_manufacturer: Option<String>,
pub device_model: Option<String>,
pub region: Option<String>,
pub debug_tag: Option<String>,
The fields should be audited, new fields added or removed.
┆Issue is synchronized with this Jira Task
.
┆Issue is synchronized with this Jira Task
I want to be able to compile this :
enum BoboType {
"TRON",
"ZORD",
};
dictionary TestMock {
BoboType name_suffix_variant;
};
┆Issue is synchronized with this Jira Task
Experimenter crate needs a way to bubble up freshly enrolled experiments into Glean, this should be done using the platform layer until we find a way to use Glean from Rust
Reference: https://sentry.prod.mozaws.net/operations/fenix-fennec/issues/9257398/events/cea5418189f54230b9ff26a7256ca841/
┆Issue is synchronized with this Jira Task
┆Issue is synchronized with this Jira Epic
One example of the known schema we have right now is at https://github.com/mozilla/nimbus-shared/blob/main/data/experiment-recipe-samples/pull-factor.json
There could be some changes to the schema in the future, but this is fairly close to what we need to support. We can do a first pass at supporting the schema above.
┆Issue is synchronized with this Jira Task
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.