Skip to content

Commit

Permalink
Merge pull request #33 from acterglobal/issue26_duration-type-support
Browse files Browse the repository at this point in the history
Add support for duration primitive type in code generation
  • Loading branch information
gnunicorn authored May 24, 2024
2 parents 78a8563 + 102dcb0 commit 434d2c7
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 3 deletions.
22 changes: 22 additions & 0 deletions fixtures/duration_type_test/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "duration_type_test"
version = "0.1.0"
edition = "2021"
publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html


[lib]
name = "duration_type_test"
crate-type = ["lib", "cdylib"]

[dependencies]
uniffi = { workspace = true }

[build-dependencies]
uniffi-dart = { path = "../../", features = ["build"] }

[dev-dependencies]
uniffi-dart = { path = "../../", features = ["bindgen-tests"] }
uniffi = { workspace = true, features = ["bindgen-tests"] }
anyhow = "1"
3 changes: 3 additions & 0 deletions fixtures/duration_type_test/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
uniffi_dart::generate_scaffolding("./src/api.udl".into()).unwrap();
}
1 change: 1 addition & 0 deletions fixtures/duration_type_test/src/api.udl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
namespace duration_type_test { };
19 changes: 19 additions & 0 deletions fixtures/duration_type_test/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use core::time::Duration;
use uniffi;

#[uniffi::export]
pub fn make_duration(seconds: u64, nanos: u32) -> Duration {
Duration::new(seconds, nanos)
}

#[uniffi::export]
pub fn get_seconds(duration: Duration) -> u64 {
duration.as_secs()
}

#[uniffi::export]
pub fn get_nanos(duration: Duration) -> u32 {
duration.subsec_nanos()
}

uniffi::include_scaffolding!("api");
35 changes: 35 additions & 0 deletions fixtures/duration_type_test/test/duration_type_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import 'package:test/test.dart';
import '../duration_type_test.dart';

void main() {
final api = Api.load();
test('rust return value seconds check', () {
final duration = api.makeDuration(5, 0);

expect(duration.inSeconds, 5);
expect(api.getSeconds(duration), 5);
expect(api.getNanos(duration), 0);
});

test('seconds data check from dart', () {
final duration = Duration(seconds: 10);
expect(api.getSeconds(duration), 10);
expect(api.getNanos(duration), 0);
});

test('check nanos/micros', () {
final duration = api.makeDuration(0, 3000);
expect(duration.inSeconds, 0);
expect(duration.inMicroseconds, 3);
expect(api.getSeconds(duration), 0);
expect(api.getNanos(duration), 3000);
});

test('check large values', () {
final duration = api.makeDuration(123456789, 3000000);
expect(duration.inSeconds, 123456789);
expect(duration.inMicroseconds, 123456789003000);
expect(api.getSeconds(duration), 123456789);
expect(api.getNanos(duration), 3000000);
});
}
6 changes: 6 additions & 0 deletions fixtures/duration_type_test/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use anyhow::Result;

#[test]
fn duration_type_test() -> Result<()> {
uniffi_dart::testing::run_test("duration_type_test", "src/api.udl", None)
}
3 changes: 3 additions & 0 deletions src/gen/oracle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ impl DartCodeOracle {
| Type::Float32
| Type::Float64 => inner,
Type::Boolean
| Type::Duration
| Type::String
| Type::Object { .. }
| Type::Enum { .. }
Expand Down Expand Up @@ -237,6 +238,7 @@ impl DartCodeOracle {
| Type::Float32
| Type::Float64 => inner,
Type::Boolean
| Type::Duration
| Type::String
| Type::Object { .. }
| Type::Enum { .. }
Expand Down Expand Up @@ -336,6 +338,7 @@ impl<T: AsType> AsCodeType for T {
Type::Float64 => Box::new(primitives::Float64CodeType),
Type::Boolean => Box::new(primitives::BooleanCodeType),
Type::String => Box::new(primitives::StringCodeType),
Type::Duration => Box::new(primitives::DurationCodeType),
Type::Object { name, .. } => Box::new(objects::ObjectCodeType::new(name)),
Type::Optional { inner_type } => Box::new(compounds::OptionalCodeType::new(
self.as_type(),
Expand Down
7 changes: 5 additions & 2 deletions src/gen/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ use uniffi_bindgen::interface::{Radix, Type};
#[macro_use]
mod macros;
mod boolean;
mod duration;
mod string;
pub use boolean::BooleanCodeType;
pub use duration::DurationCodeType;
pub use string::StringCodeType;

fn render_literal(literal: &Literal) -> String {
Expand All @@ -22,7 +24,8 @@ fn render_literal(literal: &Literal) -> String {
| Type::UInt32
| Type::UInt64
| Type::Float32
| Type::Float64 => num_str,
| Type::Float64
| Type::Duration => num_str,
_ => panic!("Unexpected literal: {} is not a number", num_str),
}
}
Expand All @@ -47,7 +50,6 @@ fn render_literal(literal: &Literal) -> String {
},
),
Literal::Float(string, type_) => typed_number(type_, string.clone()),

_ => unreachable!("Literal"),
}
}
Expand Down Expand Up @@ -143,6 +145,7 @@ pub fn generate_wrapper_lowerers() -> dart::Tokens {
return res;
}


Uint8List lowerSequence<T, V>(Api api, List<T> input, Uint8List Function(Api, V) lowerer, int element_byte_size) {
int capacity = input.length * element_byte_size;
Uint8List items = Uint8List(capacity + 4); // Four bytes for the length
Expand Down
48 changes: 48 additions & 0 deletions src/gen/primitives/duration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use crate::gen::{
quote,
render::{Renderable, TypeHelperRenderer},
};

use super::paste;
use genco::lang::dart;

impl_code_type_for_primitive!(DurationCodeType, "duration", "Duration");

impl Renderable for DurationCodeType {
fn render_type_helper(&self, _type_helper: &dyn TypeHelperRenderer) -> dart::Tokens {
quote! {
class FfiConverterDuration {
static Duration lift(Api api, RustBuffer buf) {
return FfiConverterDuration.read(api, buf.asUint8List()).value;
}

static RustBuffer lower(Api api, Duration value) {
final buf = Uint8List(12);
FfiConverterDuration.write(api, value, buf);
return toRustBuffer(api, buf);
}

static LiftRetVal<Duration> read(Api api, Uint8List buf) {
final bytes = buf.buffer.asByteData(buf.offsetInBytes, 12);
final seconds = bytes.getUint64(0);
final micros = (bytes.getUint32(8) ~/ 1000);
return LiftRetVal(Duration(seconds: seconds, microseconds: micros), 12);
}

static int allocationSize([Duration value = const Duration()]) {
return 12;
}

static int write(Api api, Duration value, Uint8List buf) {
final bytes = buf.buffer.asByteData(buf.offsetInBytes, 12);
bytes.setUint64(0, value.inSeconds);
final ms = (value.inMicroseconds - (value.inSeconds * 1000000)) * 1000;
if (ms > 0) {
bytes.setUint32(8, ms.toInt());
}
return 12;
}
}
}
}
}
4 changes: 3 additions & 1 deletion src/gen/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub trait Renderable {
Type::String => quote!(String),
Type::Object { name, .. } => quote!($name),
Type::Boolean => quote!(bool),
Type::Duration => quote!(Duration),
Type::Optional { inner_type } => quote!($(&self.render_type(inner_type, type_helper))?),
Type::Sequence { inner_type } => {
quote!(List<$(&self.render_type(inner_type, type_helper))>)
Expand Down Expand Up @@ -109,6 +110,7 @@ impl<T: AsType> AsRenderable for T {
Type::Float64 => Box::new(primitives::Float64CodeType),
Type::Boolean => Box::new(primitives::BooleanCodeType),
Type::String => Box::new(primitives::StringCodeType),
Type::Duration => Box::new(primitives::DurationCodeType),
Type::Object { name, .. } => Box::new(objects::ObjectCodeType::new(name)),
Type::Optional { inner_type, .. } => Box::new(compounds::OptionalCodeType::new(
self.as_type(),
Expand All @@ -122,10 +124,10 @@ impl<T: AsType> AsRenderable for T {
Type::Record { name, module_path } => {
Box::new(records::RecordCodeType::new(name, module_path))
}

_ => todo!("Renderable for Type::{:?}", self.as_type()), // Type::Bytes => Box::new(primitives::BytesCodeType),

// Type::Timestamp => Box::new(miscellany::TimestampCodeType),
// Type::Duration => Box::new(miscellany::DurationCodeType),

// Type::Object { name, .. } => Box::new(object::ObjectCodeType::new(name)),
// Type::Record(id) => Box::new(record::RecordCodeType::new(id)),
Expand Down
1 change: 1 addition & 0 deletions src/gen/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ pub fn generate_type(ty: &Type) -> dart::Tokens {
| Type::Int64
| Type::UInt16
| Type::Int32
| Type::Duration
| Type::UInt64 => quote!(int),
Type::Float32 | Type::Float64 => quote!(double),
Type::String => quote!(String),
Expand Down

0 comments on commit 434d2c7

Please sign in to comment.