Skip to content

Commit 875091d

Browse files
committed
fix: [Rust] Enable more tests
1 parent 6f0c46f commit 875091d

19 files changed

Lines changed: 776 additions & 265 deletions

src/Fable.Transforms/Rust/Fable2Rust.fs

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4095,16 +4095,14 @@ module Util =
40954095

40964096
let makeImportBound com ctx moduleName typeName =
40974097
let importName = getLibraryImportName com ctx moduleName typeName
4098-
let objectBound = mkTypeTraitGenericBound [ importName ] None
4099-
objectBound
4098+
mkTypeTraitGenericBound [ importName ] None
41004099

41014100
let makeRawBound id = makeGenBound [ rawIdent id ] []
41024101

41034102
let makeOpBound op =
41044103
// makes ops type bound, e.g. T: Add(Output=T)
41054104
let ty = mkGenericPathTy [ argName ] None
41064105
let genArgsOpt = mkConstraintArgs [] [ "Output", ty ]
4107-
41084106
mkTypeTraitGenericBound ("core" :: "ops" :: op :: []) genArgsOpt
41094107

41104108
let makeConstraint c =
@@ -4117,7 +4115,7 @@ module Util =
41174115
| Operators.division, true -> [ makeOpBound "Div" ]
41184116
| Operators.modulus, true -> [ makeOpBound "Rem" ]
41194117
| Operators.unaryNegation, true -> [ makeOpBound "Neg" ]
4120-
| Operators.divideByInt, true -> [ makeOpBound "Div"; makeGenBound [ rawIdent "From" ] [ "i32" ] ]
4118+
| Operators.divideByInt, true -> [ makeImportBound com ctx "Native" "DivideByInt" ]
41214119
| "get_Zero", true -> [ makeRawBound "Default" ]
41224120
| _ -> []
41234121
| Fable.Constraint.CoercesTo(targetType) ->
@@ -5043,6 +5041,7 @@ module Util =
50435041
Operators.multiply, ("bin_op", "Mul", "mul") // The multiplication operator *.
50445042
Operators.division, ("bin_op", "Div", "div") // The division operator /.
50455043
Operators.modulus, ("bin_op", "Rem", "rem") // The remainder operator %.
5044+
Operators.divideByInt, ("div_int_op", "DivideByInt", "divide_by_int") // The integer division operator DivideByInt.
50465045

50475046
Operators.bitwiseAnd, ("bin_op", "BitAnd", "bitand") // The bitwise AND operator &.
50485047
Operators.bitwiseOr, ("bin_op", "BitOr", "bitor") // The bitwise OR operator |.
@@ -5099,6 +5098,55 @@ module Util =
50995098
)
51005099
)
51015100

5101+
let makeDefaultTraitImpls
5102+
com
5103+
ctx
5104+
(ent: Fable.Entity)
5105+
entName
5106+
genArgs
5107+
(members: (Fable.MemberDecl * Fable.MemberFunctionOrValue) list)
5108+
=
5109+
// For value types that are not defaultable (e.g. unions),
5110+
// generate a Default impl delegating to the static Zero member:
5111+
//
5112+
// impl<...> core::default::Default for EntName<...> {
5113+
// fn default() -> Self { Self::get_Zero() }
5114+
// }
5115+
let needsExplicitDefault =
5116+
ent.IsValueType && not (ent |> isDefaultableEntity com Set.empty)
5117+
5118+
if not needsExplicitDefault then
5119+
[]
5120+
else
5121+
members
5122+
|> List.tryPick (fun (decl, memb) ->
5123+
if
5124+
not memb.IsInstance
5125+
&& (memb.CompiledName = "get_Zero"
5126+
|| memb.CompiledName = "Zero"
5127+
|| decl.Name = "get_Zero")
5128+
then
5129+
let zeroMemberName = Fable.Naming.splitLast decl.Name
5130+
let bodyExpr = makeCall [ "Self"; zeroMemberName ] None []
5131+
let fnBody = bodyExpr |> mkExprBlock |> Some
5132+
5133+
let fnDecl =
5134+
let output = mkGenericPathTy [ "Self" ] None |> mkFnRetTy
5135+
mkFnDecl [] output
5136+
5137+
let fnKind = mkFnKind DEFAULT_FN_HEADER fnDecl NO_GENERICS fnBody
5138+
let fnItem = mkFnAssocItem [] "default" fnKind
5139+
5140+
let path =
5141+
mkGenericPath ("core" :: "default" :: (rawIdent "Default") :: []) None None
5142+
5143+
let ofTrait = mkTraitRef path |> Some
5144+
[ fnItem ] |> makeTraitImpl com ctx entName genArgs ofTrait |> Some
5145+
else
5146+
None
5147+
)
5148+
|> Option.toList
5149+
51025150
let withCurrentScope ctx (usedNames: Set<string>) f =
51035151
let ctx =
51045152
{ ctx with UsedNames = { ctx.UsedNames with CurrentDeclarationScope = HashSet usedNames } }
@@ -5224,6 +5272,9 @@ module Util =
52245272
(baseTypeOpt, "&self." + baseName)
52255273
||> makeDerefTraitImpls com ctx entName genArgs
52265274

5275+
let defaultTraitImpls =
5276+
nonInterfaceMembers |> makeDefaultTraitImpls com ctx ent entName genArgs
5277+
52275278
let displayTraitImpls =
52285279
let hasToString =
52295280
nonInterfaceMembers |> List.exists (fun (d, m) -> m.CompiledName = "ToString")
@@ -5283,8 +5334,9 @@ module Util =
52835334
|> makeInterfaceTraitImpls com ctx entName genParams ifcEntRef ifcGenArgs
52845335
)
52855336

5286-
derefTraitImpls
5287-
@ nonInterfaceImpls
5337+
nonInterfaceImpls
5338+
@ derefTraitImpls
5339+
@ defaultTraitImpls
52885340
@ displayTraitImpls
52895341
@ operatorTraitImpls
52905342
@ refEqualityTraitImpls

src/Fable.Transforms/Rust/Replacements.fs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,8 @@ let applyOp (com: ICompiler) (ctx: Context) r t opName (args: Expr list) =
383383
| _ -> binOp BinaryMinus left right
384384
| Operators.multiply, [ left; right ] -> binOp BinaryMultiply left right
385385
| Operators.division, [ left; right ] -> binOp BinaryDivide left right
386-
| Operators.divideByInt, [ left; right ] -> binOp BinaryDivide left (TypeCast(right, t))
386+
| Operators.divideByInt, [ left; right ] ->
387+
Helper.LibCall(com, "Native", "divideByInt", t, [ left; right ], argTypes, ?loc = r)
387388
| Operators.modulus, [ left; right ] -> binOp BinaryModulus left right
388389
| Operators.leftShift, [ left; right ] -> binOp BinaryShiftLeft left right |> truncateUnsigned // See #1530
389390
| Operators.rightShift, [ left; right ] ->
@@ -950,8 +951,14 @@ let operators (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr o
950951
|> Some
951952
| "DefaultAsyncBuilder", _ -> makeImportLib com t "singleton" "AsyncBuilder" |> Some
952953
// Erased operators.
953-
// KeyValuePair is already compiled as a tuple
954-
| ("KeyValuePattern" | "Identity" | "Box" | "Unbox" | "ToEnum"), [ arg ] -> TypeCast(arg, t) |> Some
954+
// Rust compiles KeyValuePair as a struct tuple, but the KeyValue active pattern expects a regular tuple.
955+
| "KeyValuePattern", [ arg ] ->
956+
match arg.Type with
957+
| Builtin(BclKeyValuePair(keyType, valueType)) ->
958+
makeTuple r false [ Get(arg, TupleIndex 0, keyType, r); Get(arg, TupleIndex 1, valueType, r) ]
959+
|> Some
960+
| _ -> TypeCast(arg, t) |> Some
961+
| ("Identity" | "Box" | "Unbox" | "ToEnum"), [ arg ] -> TypeCast(arg, t) |> Some
955962
// Cast to unit to make sure nothing is returned when wrapped in a lambda, see #1360
956963
| "Ignore", _ -> Value(UnitConstant, r) |> Some
957964
// Number and String conversions
@@ -3123,6 +3130,8 @@ let guids
31233130
| "Parse", None, [ ExprType String ] -> Helper.LibCall(com, "Guid", "parse", t, args, ?loc = r) |> Some
31243131
| "TryParse", None, [ ExprType String; _ ] -> Helper.LibCall(com, "Guid", "tryParse", t, args, ?loc = r) |> Some
31253132
| "ToByteArray", Some x, [] -> Helper.LibCall(com, "Guid", "toByteArray", t, [ x ], ?loc = r) |> Some
3133+
| "ToString", Some x, [ ExprType String ] ->
3134+
Helper.LibCall(com, "Guid", "toStringFormat", t, [ x ] @ args, ?loc = r) |> Some
31263135
| "ToString", Some x, [] -> toString com ctx r [ x ] |> Some
31273136
// TODO: other methods and overrides
31283137
| _ -> None

src/fable-library-rust/src/BigInt.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
pub mod BigInt_ {
33
use crate::Decimal_::{decimal, truncate};
44
use crate::NativeArray_::{array_from, Array};
5-
use crate::Native_::{compare, getHashCode, Hashable, Lrc, MutCell, ToString, Vec};
5+
use crate::Native_::{compare, getHashCode, DivideByInt, Hashable, Lrc, MutCell, ToString, Vec};
66
use crate::String_::{string, toString as toString_1};
77

88
use num_bigint::*;
99
use num_integer::*;
1010
use num_traits::*;
1111

12-
#[repr(transparent)]
1312
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
13+
#[repr(transparent)]
1414
pub struct bigint(Lrc<BigInt>);
1515

1616
impl From<BigInt> for bigint {
@@ -33,6 +33,13 @@ pub mod BigInt_ {
3333
}
3434
}
3535

36+
impl DivideByInt for bigint {
37+
#[inline]
38+
fn divide_by_int(self, rhs: i32) -> Self {
39+
self / fromInt32(rhs)
40+
}
41+
}
42+
3643
impl Hashable for bigint {
3744
#[inline]
3845
fn getHashCode(&self) -> i32 {

src/fable-library-rust/src/DateOnly.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ pub mod DateOnly_ {
99
};
1010
use chrono::{DateTime as CDateTime, Datelike, Months, NaiveDate, NaiveTime, ParseResult};
1111

12-
#[repr(transparent)]
1312
#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd)]
13+
#[repr(transparent)]
1414
pub struct DateOnly(NaiveDate);
1515

1616
impl core::fmt::Display for DateOnly {

src/fable-library-rust/src/DateTime.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -456,20 +456,28 @@ pub mod DateTime_ {
456456
}
457457

458458
pub fn toString(&self, format: string) -> string {
459+
if matches!(format.as_str(), "o" | "O") {
460+
let cdt = self.to_cdt_fixed();
461+
let frac = (self.ticks() % ticks_per_second).abs();
462+
let date = cdt.format("%Y-%m-%dT%H:%M:%S");
463+
let s = match self.kind {
464+
DateTimeKind::Utc => format!("{}.{:07}Z", date, frac),
465+
DateTimeKind::Local => format!("{}.{:07}{}", date, frac, cdt.format("%:z")),
466+
DateTimeKind::Unspecified => format!("{}.{:07}", date, frac),
467+
};
468+
return fromString(s);
469+
}
470+
459471
let fmt = match format.as_str() {
460472
"" => "%m/%d/%Y %H:%M:%S".to_string(),
461473
"g" => "%m/%d/%Y %H:%M".to_string(),
462474
"G" => "%m/%d/%Y %H:%M:%S".to_string(),
463-
"o" | "O" => match self.kind {
464-
DateTimeKind::Utc => "%Y-%m-%dT%H:%M:%S%.fZ".to_string(),
465-
DateTimeKind::Local => "%Y-%m-%dT%H:%M:%S%.f%:z".to_string(),
466-
DateTimeKind::Unspecified => "%Y-%m-%dT%H:%M:%S%.f".to_string(),
467-
},
468475
//TODO: support more formats, custom formats, etc.
469476
_ => format
470477
.replace("yyyy", "%Y")
471478
.replace("MM", "%m")
472479
.replace("dd", "%d")
480+
.replace("HH", "%H")
473481
.replace("hh", "%H")
474482
.replace("mm", "%M")
475483
.replace("ss", "%S")

src/fable-library-rust/src/DateTimeOffset.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ pub mod DateTimeOffset_ {
1616
};
1717
use core::ops::{Add, Sub};
1818

19-
#[repr(transparent)]
2019
#[derive(Clone, Copy, Debug)]
20+
#[repr(transparent)]
2121
pub struct DateTimeOffset(CDateTime<FixedOffset>);
2222

2323
impl core::fmt::Display for DateTimeOffset {

src/fable-library-rust/src/Decimal.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#[cfg(feature = "decimal")]
22
pub mod Decimal_ {
3-
use crate::Native_::{compare, getHashCode, Hashable, Lrc, MutCell, Vec};
3+
use crate::Native_::{compare, getHashCode, DivideByInt, Hashable, Lrc, MutCell, Vec};
44
use crate::NativeArray_::{new_array, Array};
55
use crate::String_::{string, toString as toString_1};
66
use core::cmp::Ordering;
@@ -14,6 +14,13 @@ pub mod Decimal_ {
1414
pub const MaxValue: decimal = Decimal::MAX;
1515
pub const MinValue: decimal = Decimal::MIN;
1616

17+
impl DivideByInt for decimal {
18+
#[inline]
19+
fn divide_by_int(self, rhs: i32) -> Self {
20+
self / Decimal::from_i32(rhs).unwrap()
21+
}
22+
}
23+
1724
impl Hashable for decimal {
1825
#[inline]
1926
fn getHashCode(&self) -> i32 {

src/fable-library-rust/src/Guid.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ pub mod Guid_ {
33
use crate::DateTimeOffset_::DateTimeOffset;
44
use crate::NativeArray_::{new_array, Array};
55
use crate::Native_::{compare, getHashCode, Hashable, MutCell};
6-
use crate::String_::{string, toString};
6+
use crate::String_::{fromString, string, toString};
77
use uuid::{NoContext, Timestamp, Uuid};
88

99
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
@@ -62,6 +62,36 @@ pub mod Guid_ {
6262
new_array(&x.0.to_bytes_le())
6363
}
6464

65+
pub fn toStringFormat(x: Guid, format: string) -> string {
66+
match format.as_str() {
67+
"" | "D" | "d" => fromString(x.0.hyphenated().to_string()),
68+
"N" | "n" => fromString(x.0.simple().to_string()),
69+
"B" | "b" => fromString(format!("{{{}}}", x.0.hyphenated())),
70+
"P" | "p" => fromString(format!("({})", x.0.hyphenated())),
71+
"X" | "x" => {
72+
let bytes = x.0.as_bytes();
73+
let data1 = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
74+
let data2 = u16::from_be_bytes([bytes[4], bytes[5]]);
75+
let data3 = u16::from_be_bytes([bytes[6], bytes[7]]);
76+
fromString(format!(
77+
"{{0x{:08x},0x{:04x},0x{:04x},{{0x{:02x},0x{:02x},0x{:02x},0x{:02x},0x{:02x},0x{:02x},0x{:02x},0x{:02x}}}}}",
78+
data1,
79+
data2,
80+
data3,
81+
bytes[8],
82+
bytes[9],
83+
bytes[10],
84+
bytes[11],
85+
bytes[12],
86+
bytes[13],
87+
bytes[14],
88+
bytes[15]
89+
))
90+
}
91+
_ => panic!("Format specifier was invalid."),
92+
}
93+
}
94+
6595
pub fn create_version7() -> Guid {
6696
let dto = DateTimeOffset::utcNow();
6797
create_version7_with_timestamp(dto)

src/fable-library-rust/src/Native.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,10 @@ pub mod Native_ {
318318
Default::default()
319319
}
320320

321+
pub fn divideByInt<T: DivideByInt>(x: T, y: i32) -> T {
322+
x.divide_by_int(y)
323+
}
324+
321325
pub fn min<T: PartialOrd>(x: T, y: T) -> T {
322326
if x < y {
323327
x
@@ -594,6 +598,25 @@ pub mod Native_ {
594598
// Operator traits
595599
// -----------------------------------------------------------
596600

601+
pub trait DivideByInt: Sized {
602+
fn divide_by_int(self, rhs: i32) -> Self;
603+
}
604+
605+
macro_rules! divide_by_int_impl {
606+
($($t:ty),* $(,)?) => {
607+
$(
608+
impl DivideByInt for $t {
609+
#[inline]
610+
fn divide_by_int(self, rhs: i32) -> Self {
611+
self / (rhs as $t)
612+
}
613+
}
614+
)*
615+
};
616+
}
617+
618+
divide_by_int_impl!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64);
619+
597620
#[macro_export]
598621
macro_rules! un_op {
599622
($op_trait:ident, $op_fn:ident, $op:ident, $obj:ty, $($args:ty),*) => {
@@ -620,7 +643,20 @@ pub mod Native_ {
620643
};
621644
}
622645

646+
#[macro_export]
647+
macro_rules! div_int_op {
648+
($op_trait:ident, $op_fn:ident, $op:ident, $obj:ty, $rhs:ty, $($args:ty,)*) => {
649+
impl<$($args),*> $crate::Native_::DivideByInt for $obj {
650+
#[inline]
651+
fn divide_by_int(self, rhs: i32) -> Self {
652+
<$obj>::$op(self, rhs)
653+
}
654+
}
655+
};
656+
}
657+
623658
pub use crate::bin_op;
659+
pub use crate::div_int_op;
624660
pub use crate::un_op;
625661

626662
// -----------------------------------------------------------

src/fable-library-rust/src/String.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ pub mod String_ {
1818
mod HeapString {
1919
use crate::Native_::{Lrc, NullableRef, String};
2020

21-
#[repr(transparent)]
2221
#[derive(Clone)]
22+
#[repr(transparent)]
2323
pub struct LrcStr(Option<Lrc<str>>);
2424

2525
pub type string = LrcStr;

0 commit comments

Comments
 (0)