1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#ifndef mozilla_UniFFIFfiConverter_h
#define mozilla_UniFFIFfiConverter_h
#include <limits>
#include <type_traits>
#include "nsString.h"
#include "mozilla/ResultVariant.h"
#include "mozilla/dom/PrimitiveConversions.h"
#include "mozilla/dom/TypedArray.h"
#include "mozilla/dom/UniFFIBinding.h"
#include "mozilla/dom/UniFFIPointer.h"
#include "mozilla/dom/UniFFIScaffolding.h"
#include "mozilla/uniffi/OwnedRustBuffer.h"
#include "mozilla/uniffi/PointerType.h"
#include "mozilla/uniffi/Rust.h"
namespace mozilla::uniffi {
// This header defines the `FfiValue*` classes, which handle conversions between
// FFI values and the JS `OwningUniFFIScaffoldingValue` class.
//
// The exact signatures vary slightly, but in all FfiValue classes define these
// functions:
// - `Lower` -- Convert a `OwningUniFFIScaffoldingValue` into an `FfiValue`.
// - `Lift` -- Convert a `FfiValue` into a `OwningUniFFIScaffoldingValue`.
// - `IntoRust` -- Convert a `FfiValue` into a raw FFI type to pass to Rust
// - `FromRust` -- Convert a raw FFI type from Rust into a `FfiValue`
//
// Also, each `FfiValue` class defines a default constructor.
// For types that hold resources like `FfiValueRustBuffer`, `Lift` and
// `IntoRust` move resources out of the value, leaving behind the default.
// FfiValue class for integer values
template <typename T>
class FfiValueInt {
private:
T mValue = 0;
public:
FfiValueInt() = default;
explicit FfiValueInt(T aValue) : mValue(aValue) {}
void Lower(const dom::OwningUniFFIScaffoldingValue& aValue,
ErrorResult& aError) {
if (!aValue.IsDouble()) {
aError.ThrowTypeError("Bad argument type"_ns);
return;
}
double floatValue = aValue.GetAsDouble();
// Use PrimitiveConversionTraits_Limits rather than std::numeric_limits,
// since it handles JS-specific bounds like the 64-bit integer limits.
// (see Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER)
if (floatValue < dom::PrimitiveConversionTraits_Limits<T>::min() ||
floatValue > dom::PrimitiveConversionTraits_Limits<T>::max()) {
aError.ThrowRangeError("Integer value is out of range"_ns);
return;
}
T intValue = static_cast<T>(floatValue);
if (intValue != floatValue) {
aError.ThrowTypeError("Not an integer"_ns);
return;
}
mValue = intValue;
}
void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest,
ErrorResult& aError) {
if (mValue < dom::PrimitiveConversionTraits_Limits<T>::min() ||
mValue > dom::PrimitiveConversionTraits_Limits<T>::max()) {
aError.ThrowRangeError(
"64-bit value cannot be precisely represented in JS"_ns);
return;
}
aDest->SetAsDouble() = mValue;
}
T IntoRust() { return mValue; }
static FfiValueInt FromRust(T aValue) { return FfiValueInt(aValue); };
};
// FfiValue class for floating point values
template <typename T>
class FfiValueFloat {
private:
T mValue = 0.0;
public:
FfiValueFloat() = default;
explicit FfiValueFloat(T aValue) : mValue(aValue) {}
void Lower(const dom::OwningUniFFIScaffoldingValue& aValue,
ErrorResult& aError) {
if (!aValue.IsDouble()) {
aError.ThrowTypeError("Bad argument type"_ns);
return;
}
mValue = aValue.GetAsDouble();
}
void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest,
ErrorResult& aError) {
aDest->SetAsDouble() = mValue;
}
T IntoRust() { return mValue; }
static FfiValueFloat FromRust(T aValue) { return FfiValueFloat(aValue); }
};
class FfiValueRustBuffer {
private:
OwnedRustBuffer mValue;
public:
FfiValueRustBuffer() = default;
explicit FfiValueRustBuffer(RustBuffer aValue)
: mValue(OwnedRustBuffer(aValue)) {}
explicit FfiValueRustBuffer(OwnedRustBuffer aValue)
: mValue(std::move(aValue)) {}
void Lower(const dom::OwningUniFFIScaffoldingValue& aValue,
ErrorResult& aError) {
if (!aValue.IsArrayBuffer()) {
aError.ThrowTypeError("Expected ArrayBuffer argument"_ns);
return;
}
mValue = OwnedRustBuffer::FromArrayBuffer(aValue.GetAsArrayBuffer());
}
void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest,
ErrorResult& aError) {
JS::Rooted<JSObject*> obj(aContext);
mValue.IntoArrayBuffer(aContext, &obj, aError);
if (aError.Failed()) {
return;
}
aDest->SetAsArrayBuffer().Init(obj);
}
RustBuffer IntoRust() { return mValue.IntoRustBuffer(); }
static FfiValueRustBuffer FromRust(RustBuffer aValue) {
return FfiValueRustBuffer(OwnedRustBuffer(aValue));
}
bool IsSet() { return mValue.IsValid(); }
};
} // namespace mozilla::uniffi
#endif // mozilla_UniFFIFfiConverter_h
|