flutter_rust_bridge
flutter_rust_bridge copied to clipboard
What about constructors?
Rust does not have a built-in feature for constructors, but the norm is to define an associated function new(...)
for that type.
Dart has constructors as a feature. One can define up to one constructor and multiple named constructors. (A factory acts like a static method, returning an instance of a class, but has the same Syntax as a constructor to the class user)
Currently, on the Dart side, there is a constructor being generated that initializes all fields on the Dart side. But sometimes, the constructor on the Rust side is mandatory.
Solution
If a constructor on the Rust side should be used, generate a factory constructor that calls that constructor and do not expose the default constructor to the public API, if the struct does not have attribute #[frb(default_constructor)].
What should be considered a constructor?
- An associated function should be considered a constructor,
- if it does not have attribute
#[frb(no_constructor)]
and - if its signature is
pub fn new(...) -> Self
, whereSelf
can also be the struct type, or - if it returns
Self
or the struct type and has attribute#[frb(constructor(default))]
- if it does not have attribute
- An associated function should be considered a named constructor,
- if it does not have attribute
#[frb(no_constructor)]
and - if it returns
Self
or the struct type and its name is notnew
. The name of the constructor should be-
<name>
, if it has attribute#[frb(constructor("<name>"))]
, or - the name of the function, otherwise
-
- if its signature is
pub fn new(...) -> Self
, whereSelf
can also be the struct type and it has attribute#[frb(constructor("<name>"))]
, where the name of the constructor is<name>
.
- if it does not have attribute
Alternatives
Try to ignore the Dart constructor and only call MyStruct.newMyStruct(...)
. This is bad, if you have a public API
Additional context
Example
pub struct Point {
pub x: f64,
pub y: f64,
}
impl Point {
// Constructor
pub fn new(x: f64, y: f64) -> Point {
Self { x, y }
}
// Named constructor
pub fn all(v: f64) -> Point {
Self { x: v, y: v }
}
// Renamed named constructor
#[frb(constructor("with_magnitude"))]
pub fn with_length(x: f64, y: f64, length: f64) -> Point {
let scale = length / (x * x + y * y).sqrt();
Self {
x: x * scale,
y: y * scale,
}
}
// Not a constructor
#[frb(no_constructor)]
pub fn add(a: &Point, b: &Point) -> Point {
Self {
x: a.x + b.x,
y: a.y + b.y,
}
}
}