Skip to content

Commit

Permalink
Add timestamp and duration types (#9)
Browse files Browse the repository at this point in the history
* Add timestamp and duration types

Along with `uniffi-fixture-time` to test them

* Add codeowners file
  • Loading branch information
skeet70 authored May 31, 2024
1 parent f0450c5 commit 06138a4
Show file tree
Hide file tree
Showing 10 changed files with 244 additions and 22 deletions.
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* @IronCoreLabs/rust-dev

55 changes: 42 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ glob = "0.3"
uniffi-example-arithmetic = { git = "https://github.com/mozilla/uniffi-rs.git", branch = "main" }
uniffi-example-geometry = { git = "https://github.com/mozilla/uniffi-rs.git", branch = "main" }
uniffi-example-rondpoint = { git = "https://github.com/mozilla/uniffi-rs.git", branch = "main" }
uniffi-fixture-time = { git = "https://github.com/mozilla/uniffi-rs.git", branch = "main" }
uniffi_testing = { git = "https://github.com/mozilla/uniffi-rs.git", branch = "main" }


30 changes: 30 additions & 0 deletions src/gen_java/miscellany.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use super::CodeType;
use crate::ComponentInterface;
use paste::paste;

macro_rules! impl_code_type_for_miscellany {
($T:ty, $class_name:literal, $canonical_name:literal) => {
paste! {
#[derive(Debug)]
pub struct $T;

impl CodeType for $T {
fn type_label(&self, _ci: &ComponentInterface) -> String {
$class_name.into()
}

fn canonical_name(&self) -> String {
$canonical_name.into()
}
}
}
};
}

impl_code_type_for_miscellany!(TimestampCodeType, "java.time.Instant", "Timestamp");

impl_code_type_for_miscellany!(DurationCodeType, "java.time.Duration", "Duration");
5 changes: 3 additions & 2 deletions src/gen_java/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use uniffi_bindgen::{

mod compounds;
mod enum_;
mod miscellany;
mod object;
mod primitives;
mod record;
Expand Down Expand Up @@ -416,8 +417,8 @@ impl AsCodeType for Type {
Type::String => Box::new(primitives::StringCodeType),
Type::Bytes => unimplemented!(), //Box::new(primitives::BytesCodeType),

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

Type::Enum { name, .. } => Box::new(enum_::EnumCodeType::new(name.clone())),
Type::Object { name, imp, .. } => {
Expand Down
50 changes: 50 additions & 0 deletions src/templates/DurationHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package {{ config.package_name() }};

import java.nio.ByteBuffer;
import java.time.Instant;
import java.time.Duration;
import java.time.DateTimeException;

public enum FfiConverterDuration implements FfiConverterRustBuffer<Duration> {
INSTANCE;

@Override
public Duration read(ByteBuffer buf) {
// Type mismatch (should be u64) but we check for overflow/underflow below
long seconds = buf.getLong();
// Type mismatch (should be u32) but we check for overflow/underflow below
long nanoseconds = (long) buf.getInt();
if (seconds < 0) {
throw new DateTimeException("Duration exceeds minimum or maximum value supported by uniffi");
}
if (nanoseconds < 0) {
throw new DateTimeException("Duration nanoseconds exceed minimum or maximum supported by uniffi");
}
return Duration.ofSeconds(seconds, nanoseconds);
}

// 8 bytes for seconds, 4 bytes for nanoseconds
@Override
public long allocationSize(Duration value) {
return 12L;
}

@Override
public void write(Duration value, ByteBuffer buf) {
if (value.getSeconds() < 0) {
// Rust does not support negative Durations
throw new IllegalArgumentException("Invalid duration, must be non-negative");
}

if (value.getNano() < 0) {
// Java docs provide guarantee that nano will always be positive, so this should be impossible
// See: https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html
throw new IllegalArgumentException("Invalid duration, nano value must be non-negative");
}

// Type mismatch (should be u64) but since Rust doesn't support negative durations we should be OK
buf.putLong(value.getSeconds());
// Type mismatch (should be u32) but since values will always be between 0 and 999,999,999 it should be OK
buf.putInt(value.getNano());
}
}
52 changes: 52 additions & 0 deletions src/templates/TimestampHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package {{ config.package_name() }};

import java.nio.ByteBuffer;
import java.time.Instant;
import java.time.Duration;
import java.time.DateTimeException;

public enum FfiConverterTimestamp implements FfiConverterRustBuffer<Instant> {
INSTANCE;

@Override
public Instant read(ByteBuffer buf) {
long seconds = buf.getLong();
// Type mismatch (should be u32) but we check for overflow/underflow below
long nanoseconds = (long) buf.getInt();
if (nanoseconds < 0) {
throw new DateTimeException("Instant nanoseconds exceed minimum or maximum supported by uniffi");
}
if (seconds >= 0) {
return Instant.EPOCH.plus(Duration.ofSeconds(seconds, nanoseconds));
} else {
return Instant.EPOCH.minus(Duration.ofSeconds(-seconds, nanoseconds));
}
}

// 8 bytes for seconds, 4 bytes for nanoseconds
@Override
public long allocationSize(Instant value) {
return 12L;
}

@Override
public void write(Instant value, ByteBuffer buf) {
Duration epochOffset = Duration.between(Instant.EPOCH, value);

var sign = 1;
if (epochOffset.isNegative()) {
sign = -1;
epochOffset = epochOffset.negated();
}

if (epochOffset.getNano() < 0) {
// Java docs provide guarantee that nano will always be positive, so this should be impossible
// See: https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html
throw new IllegalArgumentException("Invalid timestamp, nano value must be non-negative");
}

buf.putLong(sign * epochOffset.getSeconds());
// Type mismatch (should be u32) but since values will always be between 0 and 999,999,999 it should be OK
buf.putInt(epochOffset.getNano());
}
}
12 changes: 6 additions & 6 deletions src/templates/Types.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ private NoPointer() {}
{% include "ErrorTemplate.java" %}
{%- endif -%}

{%- when Type::Duration %}
{% include "DurationHelper.java" %}

{%- when Type::Int64 or Type::UInt64 %}
{%- include "Int64Helper.java" %}

Expand Down Expand Up @@ -108,6 +111,9 @@ private NoPointer() {}
{%- when Type::Sequence { inner_type } %}
{% include "SequenceTemplate.java" %}

{%- when Type::Timestamp %}
{% include "TimestampHelper.java" %}

{# TODO(murph): implement the rest of the types

{%- when Type::Bytes %}
Expand All @@ -116,12 +122,6 @@ private NoPointer() {}
{%- when Type::CallbackInterface { module_path, name } %}
{% include "CallbackInterfaceTemplate.kt" %}

{%- when Type::Timestamp %}
{% include "TimestampHelper.kt" %}

{%- when Type::Duration %}
{% include "DurationHelper.kt" %}

{%- when Type::Custom { module_path, name, builtin } %}
{% include "CustomTypeTemplate.kt" %}

Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ fixture_tests! {
// (test_todolist, "uniffi-example-todolist", "scripts/test_todolist.java"),
// (test_sprites, "uniffi-example-sprites", "scripts/test_sprites.java"),
// (test_coverall, "uniffi-fixture-coverall", "scripts/test_coverall.java"),
// (test_chronological, "uniffi-fixture-time", "scripts/test_chronological.java"),
(test_chronological, "uniffi-fixture-time", "scripts/TestChronological.java"),
// (test_custom_types, "uniffi-example-custom-types", "scripts/test_custom_types.java"),
// (test_callbacks, "uniffi-fixture-callbacks", "scripts/test_callbacks.java"),
// (test_external_types, "uniffi-fixture-ext-types", "scripts/test_imported_types.java"),
Expand Down
Loading

0 comments on commit 06138a4

Please sign in to comment.