Skip to content

Commit dd0e519

Browse files
stepanchegfacebook-github-bot
authored andcommitted
Derive UnpackValue for NumRef
Summary: Roughly the same amount of code, but easier to work with (planning to change `StarlarkTypeRepr`, and what is generated won't have to be migrated). Reviewed By: JakobDegen Differential Revision: D59378997 fbshipit-source-id: 8d8c3591d53b9425b1065c006f2fd14b0ca8bf38
1 parent 4f472bc commit dd0e519

File tree

4 files changed

+66
-73
lines changed

4 files changed

+66
-73
lines changed

starlark/src/stdlib/funcs/other.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ pub(crate) fn register_other(builder: &mut GlobalsBuilder) {
557557
match num_or_bool {
558558
Either::Left(NumRef::Int(_)) => Ok(ValueOfUnchecked::new(a.value)),
559559
Either::Left(NumRef::Float(f)) => Ok(ValueOfUnchecked::new(
560-
heap.alloc(StarlarkInt::from_f64_exact(f.trunc())?),
560+
heap.alloc(StarlarkInt::from_f64_exact(f.0.trunc())?),
561561
)),
562562
Either::Right(b) => Ok(ValueOfUnchecked::new(heap.alloc(b as i32))),
563563
}

starlark/src/values/num/value.rs

Lines changed: 46 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,16 @@ use std::ops::Mul;
2121
use std::ops::Sub;
2222

2323
use dupe::Dupe;
24-
use either::Either;
2524

2625
use crate as starlark;
2726
use crate::collections::StarlarkHashValue;
28-
use crate::typing::Ty;
2927
use crate::values::type_repr::StarlarkTypeRepr;
3028
use crate::values::types::float::StarlarkFloat;
3129
use crate::values::types::int_or_big::StarlarkInt;
3230
use crate::values::types::int_or_big::StarlarkIntRef;
3331
use crate::values::AllocFrozenValue;
3432
use crate::values::AllocValue;
3533
use crate::values::UnpackValue;
36-
use crate::values::Value;
37-
use crate::values::ValueLike;
3834

3935
#[derive(Debug, thiserror::Error)]
4036
enum NumError {
@@ -47,10 +43,11 @@ enum NumError {
4743
/// It's an intermediate representation that facilitates conversions between
4844
/// numerical types and helps in implementation of arithmetical operations
4945
/// between them.
50-
#[derive(Clone, Debug, Dupe, Copy)]
46+
#[derive(Clone, Debug, Dupe, Copy, StarlarkTypeRepr, UnpackValue)]
5147
pub(crate) enum NumRef<'v> {
5248
Int(StarlarkIntRef<'v>),
53-
Float(f64),
49+
// `StarlarkFloat` not `f64` here because `f64` unpacks from `int` too.
50+
Float(StarlarkFloat),
5451
}
5552

5653
#[derive(
@@ -65,35 +62,12 @@ pub(crate) enum Num {
6562
Float(f64),
6663
}
6764

68-
impl<'v> StarlarkTypeRepr for NumRef<'v> {
69-
fn starlark_type_repr() -> Ty {
70-
Either::<StarlarkIntRef, StarlarkFloat>::starlark_type_repr()
71-
}
72-
}
73-
74-
impl<'v> UnpackValue<'v> for NumRef<'v> {
75-
fn expected() -> String {
76-
"int or float".to_owned()
77-
}
78-
79-
#[allow(clippy::manual_map)]
80-
fn unpack_value(value: Value<'v>) -> Option<Self> {
81-
if let Some(i) = StarlarkIntRef::unpack_value(value) {
82-
Some(NumRef::Int(i))
83-
} else if let Some(f) = value.downcast_ref::<StarlarkFloat>() {
84-
Some(NumRef::Float(f.0))
85-
} else {
86-
None
87-
}
88-
}
89-
}
90-
9165
impl<'v> NumRef<'v> {
9266
/// Get underlying value as float
9367
pub(crate) fn as_float(&self) -> f64 {
9468
match self {
9569
Self::Int(i) => i.to_f64(),
96-
Self::Float(f) => *f,
70+
Self::Float(f) => f.0,
9771
}
9872
}
9973

@@ -106,7 +80,7 @@ impl<'v> NumRef<'v> {
10680
pub(crate) fn as_int(&self) -> Option<i32> {
10781
match self {
10882
Self::Int(i) => i.to_i32(),
109-
Self::Float(f) => Self::f64_to_i32_exact(*f),
83+
Self::Float(f) => Self::f64_to_i32_exact(f.0),
11084
}
11185
}
11286

@@ -129,7 +103,7 @@ impl<'v> NumRef<'v> {
129103
match (self.as_int(), self) {
130104
// equal ints and floats should have the same hash
131105
(Some(i), _) => i as u64,
132-
(None, Self::Float(f)) => float_hash(f),
106+
(None, Self::Float(f)) => float_hash(f.0),
133107
(None, Self::Int(StarlarkIntRef::Small(i))) => {
134108
// shouldn't happen - as_int() should have resulted in an int
135109
i.to_i32() as u64
@@ -150,7 +124,7 @@ impl<'v> NumRef<'v> {
150124
fn to_owned(self) -> Num {
151125
match self {
152126
NumRef::Int(i) => Num::Int(i.to_owned()),
153-
NumRef::Float(f) => Num::Float(f),
127+
NumRef::Float(f) => Num::Float(f.0),
154128
}
155129
}
156130

@@ -183,7 +157,7 @@ impl<'v> NumRef<'v> {
183157

184158
impl<'v> From<f64> for NumRef<'v> {
185159
fn from(f: f64) -> Self {
186-
Self::Float(f)
160+
Self::Float(StarlarkFloat(f))
187161
}
188162
}
189163

@@ -255,6 +229,7 @@ mod tests {
255229

256230
use super::*;
257231
use crate::values::types::inline_int::InlineInt;
232+
use crate::values::Value;
258233

259234
#[test]
260235
fn test_from_value() {
@@ -298,8 +273,8 @@ mod tests {
298273
InlineInt::MIN.to_f64()
299274
);
300275

301-
assert_eq!(NumRef::Float(0.0).as_float(), 0.0);
302-
assert!(NumRef::Float(f64::NAN).as_float().is_nan());
276+
assert_eq!(NumRef::Float(StarlarkFloat(0.0)).as_float(), 0.0);
277+
assert!(NumRef::Float(StarlarkFloat(f64::NAN)).as_float().is_nan());
303278
}
304279

305280
#[test]
@@ -317,55 +292,70 @@ mod tests {
317292
Some(-42)
318293
);
319294

320-
assert_eq!(NumRef::Float(0_f64).as_int(), Some(0));
321-
assert_eq!(NumRef::Float(42_f64).as_int(), Some(42));
322-
assert_eq!(NumRef::Float(-42_f64).as_int(), Some(-42));
295+
assert_eq!(NumRef::Float(StarlarkFloat(0_f64)).as_int(), Some(0));
296+
assert_eq!(NumRef::Float(StarlarkFloat(42_f64)).as_int(), Some(42));
297+
assert_eq!(NumRef::Float(StarlarkFloat(-42_f64)).as_int(), Some(-42));
323298

324-
assert_eq!(NumRef::Float(i32::MIN as f64).as_int(), Some(i32::MIN));
325-
assert_eq!(NumRef::Float(i32::MAX as f64).as_int(), Some(i32::MAX));
299+
assert_eq!(
300+
NumRef::Float(StarlarkFloat(i32::MIN as f64)).as_int(),
301+
Some(i32::MIN)
302+
);
303+
assert_eq!(
304+
NumRef::Float(StarlarkFloat(i32::MAX as f64)).as_int(),
305+
Some(i32::MAX)
306+
);
326307

327-
assert_eq!(NumRef::Float(42.75).as_int(), None);
328-
assert_eq!(NumRef::Float(-42.75).as_int(), None);
329-
assert_eq!(NumRef::Float(f64::NAN).as_int(), None);
330-
assert_eq!(NumRef::Float(f64::INFINITY).as_int(), None);
331-
assert_eq!(NumRef::Float(f64::NEG_INFINITY).as_int(), None);
308+
assert_eq!(NumRef::Float(StarlarkFloat(42.75)).as_int(), None);
309+
assert_eq!(NumRef::Float(StarlarkFloat(-42.75)).as_int(), None);
310+
assert_eq!(NumRef::Float(StarlarkFloat(f64::NAN)).as_int(), None);
311+
assert_eq!(NumRef::Float(StarlarkFloat(f64::INFINITY)).as_int(), None);
312+
assert_eq!(
313+
NumRef::Float(StarlarkFloat(f64::NEG_INFINITY)).as_int(),
314+
None
315+
);
332316
}
333317

334318
#[test]
335319
fn test_hashing() {
336320
assert_eq!(
337321
NumRef::Int(StarlarkIntRef::Small(InlineInt::testing_new(0))).get_hash_64(),
338-
NumRef::Float(0.0).get_hash_64()
322+
NumRef::Float(StarlarkFloat(0.0)).get_hash_64()
339323
);
340324
assert_eq!(
341325
NumRef::Int(StarlarkIntRef::Small(InlineInt::testing_new(42))).get_hash_64(),
342-
NumRef::Float(42.0).get_hash_64()
326+
NumRef::Float(StarlarkFloat(42.0)).get_hash_64()
343327
);
344328

345329
assert_eq!(
346-
NumRef::Float(f64::INFINITY + f64::NEG_INFINITY).get_hash_64(),
347-
NumRef::Float(f64::NAN).get_hash_64()
330+
NumRef::Float(StarlarkFloat(f64::INFINITY + f64::NEG_INFINITY)).get_hash_64(),
331+
NumRef::Float(StarlarkFloat(f64::NAN)).get_hash_64()
348332
);
349333
assert_eq!(
350-
NumRef::Float("0.25".parse().unwrap()).get_hash_64(),
351-
NumRef::Float("25e-2".parse().unwrap()).get_hash_64()
334+
NumRef::Float(StarlarkFloat("0.25".parse().unwrap())).get_hash_64(),
335+
NumRef::Float(StarlarkFloat("25e-2".parse().unwrap())).get_hash_64()
352336
);
353337

354338
let x = 1u64 << 55;
355339
assert_eq!(x as f64 as u64, x, "Self-check");
356340
assert_eq!(
357-
NumRef::Float(x as f64).get_hash_64(),
341+
NumRef::Float(StarlarkFloat(x as f64)).get_hash_64(),
358342
NumRef::Int(StarlarkInt::from(BigInt::from(x)).as_ref()).get_hash_64(),
359343
)
360344
}
361345

362346
#[test]
363347
fn test_eq() {
364-
assert_eq!(NumRef::Float(f64::NAN), NumRef::Float(f64::NAN));
365-
assert_eq!(NumRef::Float(f64::INFINITY), NumRef::Float(f64::INFINITY));
348+
assert_eq!(
349+
NumRef::Float(StarlarkFloat(f64::NAN)),
350+
NumRef::Float(StarlarkFloat(f64::NAN))
351+
);
352+
assert_eq!(
353+
NumRef::Float(StarlarkFloat(f64::INFINITY)),
354+
NumRef::Float(StarlarkFloat(f64::INFINITY))
355+
);
366356
assert_eq!(
367357
NumRef::Int(StarlarkIntRef::Small(InlineInt::testing_new(10))),
368-
NumRef::Float(10.0)
358+
NumRef::Float(StarlarkFloat(10.0))
369359
);
370360
}
371361
}

starlark/src/values/types/float.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ impl Display for StarlarkFloat {
265265
#[starlark_value(type = StarlarkFloat::TYPE)]
266266
impl<'v> StarlarkValue<'v> for StarlarkFloat {
267267
fn equals(&self, other: Value) -> crate::Result<bool> {
268-
Ok(Some(NumRef::Float(self.0)) == other.unpack_num())
268+
Ok(Some(NumRef::Float(StarlarkFloat(self.0))) == other.unpack_num())
269269
}
270270

271271
fn collect_repr(&self, s: &mut String) {
@@ -282,7 +282,7 @@ impl<'v> StarlarkValue<'v> for StarlarkFloat {
282282
}
283283

284284
fn get_hash(&self, _private: Private) -> crate::Result<StarlarkHashValue> {
285-
Ok(NumRef::Float(self.0).get_hash())
285+
Ok(NumRef::Float(*self).get_hash())
286286
}
287287

288288
fn plus(&self, heap: &'v Heap) -> crate::Result<Value<'v>> {
@@ -294,38 +294,38 @@ impl<'v> StarlarkValue<'v> for StarlarkFloat {
294294
}
295295

296296
fn add(&self, other: Value, heap: &'v Heap) -> Option<crate::Result<Value<'v>>> {
297-
Some(Ok(heap.alloc(NumRef::Float(self.0) + other.unpack_num()?)))
297+
Some(Ok(heap.alloc(NumRef::Float(*self) + other.unpack_num()?)))
298298
}
299299

300300
fn sub(&self, other: Value, heap: &'v Heap) -> crate::Result<Value<'v>> {
301301
match other.unpack_num() {
302302
None => ValueError::unsupported_with(self, "-", other),
303-
Some(other) => Ok(heap.alloc(NumRef::Float(self.0) - other)),
303+
Some(other) => Ok(heap.alloc(NumRef::Float(*self) - other)),
304304
}
305305
}
306306

307307
fn mul(&self, other: Value<'v>, heap: &'v Heap) -> Option<crate::Result<Value<'v>>> {
308-
Some(Ok(heap.alloc(NumRef::Float(self.0) * other.unpack_num()?)))
308+
Some(Ok(heap.alloc(NumRef::Float(*self) * other.unpack_num()?)))
309309
}
310310

311311
fn div(&self, other: Value, heap: &'v Heap) -> crate::Result<Value<'v>> {
312312
match other.unpack_num() {
313313
None => ValueError::unsupported_with(self, "/", other),
314-
Some(other) => Ok(heap.alloc(NumRef::Float(self.0).div(other)?)),
314+
Some(other) => Ok(heap.alloc(NumRef::Float(*self).div(other)?)),
315315
}
316316
}
317317

318318
fn percent(&self, other: Value, heap: &'v Heap) -> crate::Result<Value<'v>> {
319319
match other.unpack_num() {
320-
Some(other) => Ok(heap.alloc(NumRef::Float(self.0).percent(other)?)),
320+
Some(other) => Ok(heap.alloc(NumRef::Float(*self).percent(other)?)),
321321
None => ValueError::unsupported_with(self, "%", other),
322322
}
323323
}
324324

325325
fn floor_div(&self, other: Value, heap: &'v Heap) -> crate::Result<Value<'v>> {
326326
match other.unpack_num() {
327327
None => ValueError::unsupported_with(self, "//", other),
328-
Some(other) => Ok(heap.alloc(NumRef::Float(self.0).floor_div(other)?)),
328+
Some(other) => Ok(heap.alloc(NumRef::Float(*self).floor_div(other)?)),
329329
}
330330
}
331331

@@ -336,7 +336,7 @@ impl<'v> StarlarkValue<'v> for StarlarkFloat {
336336
fn compare(&self, other: Value) -> crate::Result<Ordering> {
337337
match other.unpack_num() {
338338
None => ValueError::unsupported_with(self, "compare", other),
339-
Some(other) => Ok(NumRef::Float(self.0).cmp(&other)),
339+
Some(other) => Ok(NumRef::Float(*self).cmp(&other)),
340340
}
341341
}
342342
}

starlark/src/values/types/string/interpolation.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use num_traits::Signed;
2525
use thiserror::Error;
2626

2727
use crate::values::float;
28+
use crate::values::float::StarlarkFloat;
2829
use crate::values::num::value::NumRef;
2930
use crate::values::string::dot_format::format_one;
3031
use crate::values::types::int_or_big::StarlarkIntRef;
@@ -233,10 +234,12 @@ pub(crate) fn percent(format: &str, value: Value) -> crate::Result<String> {
233234
Some(NumRef::Int(StarlarkIntRef::Big(v))) => {
234235
write!(res, "{}", v.get()).unwrap()
235236
}
236-
Some(NumRef::Float(v)) => match NumRef::Float(v.trunc()).as_int() {
237-
Some(v) => write!(res, "{}", v).unwrap(),
238-
None => ValueError::unsupported_type(value, "format(%d)")?,
239-
},
237+
Some(NumRef::Float(v)) => {
238+
match NumRef::Float(StarlarkFloat(v.0.trunc())).as_int() {
239+
Some(v) => write!(res, "{}", v).unwrap(),
240+
None => ValueError::unsupported_type(value, "format(%d)")?,
241+
}
242+
}
240243
None => ValueError::unsupported_type(value, "format(%d)")?,
241244
}
242245
}
@@ -519,15 +522,15 @@ mod tests {
519522

520523
assert::fail(
521524
"'%e' % (True,)",
522-
"Type of parameters mismatch, expected `int or float`, actual `bool`",
525+
"Type of parameters mismatch, expected `float | int`, actual `bool`",
523526
);
524527
assert::fail(
525528
"'%e' % ('abc',)",
526-
"Type of parameters mismatch, expected `int or float`, actual `string`",
529+
"Type of parameters mismatch, expected `float | int`, actual `string`",
527530
);
528531
assert::fail(
529532
"'%e' % ([],)",
530-
"Type of parameters mismatch, expected `int or float`, actual `list`",
533+
"Type of parameters mismatch, expected `float | int`, actual `list`",
531534
);
532535
}
533536

0 commit comments

Comments
 (0)