-
Notifications
You must be signed in to change notification settings - Fork 249
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add default literals for optional
arguments
#283
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving this here for feedback before a rebase.
Literal::EmptyMap => "{}".into(), | ||
|
||
_ => panic!("Literal unsupported by python"), | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd do more with numbers, but the test_rondpoint.py
is quite far behind the kotlin and swift versions right now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think my list of "things I want to do before revisiting this python patch" is back down to zero, fingers crossed...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add this to the list of things to do after #214 has landed.
match radix { | ||
Radix::Octal => format!("0o{:o}", i), | ||
Radix::Decimal => format!("{}", i), | ||
Radix::Hexadecimal => format!("{:#x}", i), | ||
}, | ||
)?, | ||
Literal::UInt(i, radix, type_) => typed_number( | ||
type_, | ||
match radix { | ||
Radix::Octal => format!("0o{:o}", i), | ||
Radix::Decimal => format!("{}", i), | ||
Radix::Hexadecimal => format!("{:#x}", i), | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This level of duplication felt acceptable.
Using the 8 byte u64
, i64
and f64
as internal representations for number literals was the compromise between lots of duplication, and flexibility of representation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds like a fine idea! This reads very cleanly, and I think the duplication trade-off is more than okay.
@@ -358,7 +358,7 @@ extension Dictionary: ViaFfiUsingByteBuffer, ViaFfi, Serializable where Key == S | |||
let len: UInt32 = try buf.readInt() | |||
var dict = [String: Value]() | |||
dict.reserveCapacity(Int(len)) | |||
for _ in 1...len { | |||
for _ in 0..<len { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests found that empty lists crashes the swift bindings.
uniffi_bindgen/src/interface/mod.rs
Outdated
}; | ||
|
||
let trimmer = Regex::new("^(-?)(0x)?").unwrap(); | ||
let string = trimmer.replace_all(string, "$1").to_lowercase(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possible improvement/optimization: putting this in a lazy_static!
macro.
uniffi_bindgen/src/interface/mod.rs
Outdated
(weedle::literal::DefaultValue::String(s), Type::Enum(_)) => { | ||
Literal::Enum(s.0.to_string(), type_.clone()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was very pleased to work out we could default enums.
a477d03
to
b2ce9ee
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't dig too much into the nitty-gritty parsing details, but did an initial high-level pass and left some comments. Overall, seems to be coming together nicely 👍
@@ -168,4 +168,93 @@ impl Stringifier { | |||
} | |||
} | |||
|
|||
#[derive(Debug, Clone)] | |||
struct Optionneur; | |||
impl Optionneur { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This rondpoint example continues to be a thing of great beauty 👍
Literal::EmptyMap => "{}".into(), | ||
|
||
_ => panic!("Literal unsupported by python"), | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think my list of "things I want to do before revisiting this python patch" is back down to zero, fingers crossed...
uniffi_bindgen/src/interface/mod.rs
Outdated
}) | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Hash)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: as of latest main
, you'll need to remove Serialize
and Deserialize
from here.
uniffi_bindgen/src/interface/mod.rs
Outdated
let src_radix = radix as u32; | ||
// This radix tells the backends how to represent the number in the output languages. | ||
let dest_radix = if string == "0" || string.starts_with('-') { | ||
// 1. weedle parses "0" as an octal literal, but we most likely want to treat this as a decimal. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wow; octal zero I hope 😬
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:D Yeah. Thought that'd be a bit surprising to our API consumers finding 0o0
in the API.
uniffi_bindgen/src/interface/mod.rs
Outdated
Decimal = 10, | ||
Octal = 8, | ||
Hexadecimal = 16, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is preserving the radix necessary for correctness in some cases, or is it entirely about readability of the generated code? (I'm not opposed to doing it for readability reasons, just want to make sure I understand).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Preserving the radix is only for readabilty/documentation for the generated interfaces.
There are cases when we can't preserve radix (octal numbers, anyone?), or our choice of representation mean that it's not possible (negative hex and octal numbers); in both these cases we use decimal because correctness beats readability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a comment about radices.
uniffi_bindgen/src/interface/mod.rs
Outdated
weedle::literal::DefaultValue::Boolean(b) => Literal::Boolean(b.0), | ||
weedle::literal::DefaultValue::String(s) => Literal::String(s.0.to_string()), | ||
_ => bail!("no support for {:?} literal yet", self), | ||
impl TypedAPIConverter<Literal> for weedle::literal::DefaultValue<'_> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you only impl
this for a single type, I wonder if it would be simpler to have convert_default_value
as a standalone function to begin with, rather than making it a trait. Or, do you anticipate adding more impl
s for this shortly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not anticipating any additional implementations. I've made the change to a standalone function as suggested.
// TODO: more types of literal | ||
UInt(u64, Radix, Type), | ||
Int(i64, Radix, Type), | ||
Float(String, Type), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naively, I was expecting to see separate UInt8
, UInt16
etc variants on this enum. I don't object to this more succinct representation if it makes the code cleaner, but it may be worth a short comment here to explain the choice since it stands out as being a bit different from other type-related enums.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added extra comments around these representations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the extra comments! I also like your approach of using the widest representation possible, and truncating to the actual type in the binding backends, to simplify the code.
b2ce9ee
to
330588d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, this is fantastic, @jhugman! Everything looks solid, and the battery of tests is great.
It would be super helpful to have for the JS and C++ backends, too, which already have some machinery for returning a dummy default value for methods that throw a JS exception—all that code can piggyback on your default literals now.
Ship it!
u64 sinon_u64_dec(optional u64 value = 42); | ||
i64 sinon_i64_dec(optional i64 value = 42); | ||
|
||
// Hexadecimal, including negatgives. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Hexadecimal, including negatgives. | |
// Hexadecimal, including negatives. |
|
||
Ok(match literal { | ||
Literal::Boolean(v) => format!("{}", v), | ||
Literal::String(s) => format!("\"{}\"", s), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to worry about escaping internal quotes (maybe more of an issue for Python single-quoted strings), or handling binary or Unicode escape sequences? It's definitely an edge case, especially for Nimbus and our other Rust components, so "no" is a totally acceptable answer—but it came to mind reading this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😷
It appears weedle doesn't let us escape quotes,
/// Represents a string value
///
/// Follow `/"[^"]*"/`
#[derive(Copy)]
struct StringLit<'a>(
&'a str = ws!(do_parse!(
char!('"') >>
s: take_while!(|c| c != '"') >>
char!('"') >>
(s)
)),
)
I added some comments at the frontend, and changed the quotes in the python backend.
pub fn literal_kt(literal: &Literal) -> Result<String, askama::Error> { | ||
fn typed_number(type_: &Type, num_str: String) -> Result<String, askama::Error> { | ||
Ok(match type_ { | ||
// special case Int32. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, did this comment come from the Swift backend?
match radix { | ||
Radix::Octal => format!("0o{:o}", i), | ||
Radix::Decimal => format!("{}", i), | ||
Radix::Hexadecimal => format!("{:#x}", i), | ||
}, | ||
)?, | ||
Literal::UInt(i, radix, type_) => typed_number( | ||
type_, | ||
match radix { | ||
Radix::Octal => format!("0o{:o}", i), | ||
Radix::Decimal => format!("{}", i), | ||
Radix::Hexadecimal => format!("{:#x}", i), | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds like a fine idea! This reads very cleanly, and I think the duplication trade-off is more than okay.
let src_radix = radix as u32; | ||
// This radix tells the backends how to represent the number in the output languages. | ||
let dest_radix = if string == "0" || string.starts_with('-') { | ||
// 1. weedle parses "0" as an octal literal, but we most likely want to treat this as a decimal. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😬 at "parses '0' as an octal literal"
uniffi_bindgen/src/interface/mod.rs
Outdated
radix | ||
}; | ||
|
||
let trimmer = Regex::new("^(-?)(0x)?").unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not too worried about this, since we're still prototyping and might eventually use more complex regexes elsewhere—but bringing in regex
can bump up compile times. For prefix-stripping like this, I wonder if we can use plain-ol' string functions, maybe something like this:
let string = if string.starts_with('-') {
("-".to_string() + string[1..].strip_prefix("0x").unwrap_or(&string[1..])).to_lowercase()
} else {
string.strip_prefix("0x").unwrap_or(&string).to_lowercase()
};
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, magic.
Not since Java 1.3 have I had to think about not having regular expressions.
// TODO: more types of literal | ||
UInt(u64, Radix, Type), | ||
Int(i64, Radix, Type), | ||
Float(String, Type), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the extra comments! I also like your approach of using the widest representation possible, and truncating to the actual type in the binding backends, to simplify the code.
330588d
to
eed96d0
Compare
Fixes #263.
This PR fleshes out the parsing and output of Literals, and used in default arguments and defaulted values for dictionaries. This corresponds to the WebIDL keyword
optional
.