-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Generate getters for all WebIDL dictionary types and deprecate builder-pattern style setters #3993
Conversation
crates/webidl/src/lib.rs
Outdated
let return_ty = | ||
optional_return_ty(idl_type.to_syn_type(TypePosition::Return).unwrap().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.
Is it really necessary for all getters to return Option
, even those for required
fields? #3937 was only talking about fields with default values, required
fields should be fine since their values have to be passed into the dictionary's new
function. For example, AudioBufferOptions::new
requires length
and sample_rate
to be passed in unconditionally due to them being required
.
On a semi-related note, it seems like required/optional fields aren't annotated for returned dictionaries, which means that we'll end up with their getters returning Option
even if the fields are always guaranteed to be present. From https://webidl.spec.whatwg.org/#idl-dictionaries:
Note that specifying dictionary members as required only has an observable effect when converting other representations of dictionaries (like a JavaScript value supplied as an argument to an operation) to an IDL dictionary. Specification authors should leave the members optional in all other cases, including when a dictionary type is used solely as the return type of operations.
I think what the spec means here is that it doesn't introduce any extra info beyond what's already in the spec text: it's just a spec-level assertion, unlike marking fields required
on dictionaries passed as arguments which causes a runtime check that those fields are present.
But it's annoying for us because it means there's no machine-readable way to tell, similar to [Throws]
. I'm not sure if it'd be better to add a similar annotation here or just let everything be optional.
I think another part of the reason is because of dictionaries that are used in both argument and return positions, where fields might be optional when used as an argument but required as a return value. And there are instances of this, e.g. MediaStreamContraints
uses fields with default values, which effectively means that they're optional when passed as an argument but required when returned.
So in scenarios like that the getters would have to return Option
. (Note that web-sys
only contains 5 dictionaries that are used as both arguments and return values right now: MediaStreamConstraints
, MediaTrackConstraints
, RTCConfiguration
, RTCRtpParameters
, and VideoColorSpaceInit
.)
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.
But it's annoying for us because it means there's no machine-readable way to tell, similar to
[Throws]
. I'm not sure if it'd be better to add a similar annotation here or just let everything be optional.
I think it would be nice to add an annotation for these use-cases, but we would have to do it now because it would be a breaking change later. Considering you already looked at this, do you think its feasible to quickly identify those dictionaries and mark them correctly or is it too big of a task?
And there are instances of this, e.g.
MediaStreamContraints
uses fields with default values, which effectively means that they're optional when passed as an argument but required when returned.
Considering that we don't have two different types, one for use as an argument and a different one for use as a return value, I agree that in this case it just has to return Option
.
I will go ahead and at least let required fields not return Option
.
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 will go ahead and at least let required fields not return
Option
.
Done.
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 it would be nice to add an annotation for these use-cases, but we would have to do it now because it would be a breaking change later. Considering you already looked at this, do you think its feasible to quickly identify those dictionaries and mark them correctly or is it too big of a task?
There aren't too many dictionaries that are used as return types, so I think it should be feasible; this is the full list:
AuthenticationExtensionsClientOutputs
ComputedEffectTiming
DOMQuadJSON
DisplayNameResult
EffectTiming
FontFaceSetIteratorResult
LocaleInfo
MediaKeySystemConfiguration
MediaStreamConstraints
MediaTrackCapabilities
MediaTrackConstraints
MediaTrackSettings
MediaTrackSupportedConstraints
PushSubscriptionJSON
RTCConfiguration
RTCRtpParameters
SerialPortInfo
TreeCellInfo
VideoColorSpaceInit
I generated this by just adding some logging to `wasm-bindgen-webidl`:
diff --git a/crates/webidl/src/util.rs b/crates/webidl/src/util.rs
index 3e8cce3e4..94dddd51c 100644
--- a/crates/webidl/src/util.rs
+++ b/crates/webidl/src/util.rs
@@ -330,6 +330,9 @@ impl<'src> FirstPassRecord<'src> {
// do this much earlier to avoid all the above work if
// possible.
let ret_ty = signature.orig.ret.to_idl_type(self);
+ if let IdlType::Dictionary(name) = ret_ty {
+ println!("{name} used in return position")
+ }
let mut rust_name = snake_case_ident(name);
let mut first = true;
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.
Done!
Also deprecated/removed their constructors, e.g. otherwise you can just write EffectTiming::new().get_fill()
and it would fail.
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.
Actually, I just realized, that there should be a ton of dictionaries returned from readonly attribute
s that would fall into this category as well. Additionally, dictionaries can be wrapped in Promise
or sequence
that we didn't consider here as well.
Ideally we should programmatically detect dictionaries that are never used as a parameter?
In any case, I'm going to revisit this again tomorrow.
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.
Just saw in CI that we can't deprecate EffectTiming::default()
, so that's also less then ideal.
EDIT: Just realized this was very unclear. I wanted to say that we can't deprecated the Default
implementation because deprecating trait implementations is not supported by Rust. See rust-lang/rust#39935.
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.
Also deprecated/removed their constructors, e.g. otherwise you can just write
EffectTiming::new().get_fill()
and it would fail.
In the long-term, it might make sense to take all the fields as arguments to new
the same as regular required
fields. For the moment though, I'm not sure if there's enough need to construct return-only dictionaries to warrant adding a second constructor (which would have to be named something awkward like new2
), and we could always add it later.
Actually, I just realized, that there should be a ton of dictionaries returned from
readonly attribute
s that would fall into this category as well. Additionally, dictionaries can be wrapped inPromise
orsequence
that we didn't consider here as well.
Good point, I didn't think of that.
Ideally we should programmatically detect dictionaries that are never used as a parameter?
Yeah, that would be better.
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.
See daxpedda@0d4bd7e.
I believe that should be pretty accurate from what we can extract from the WebIDL we have.
List of Dictionaries
DOMQuadJSON
EcdsaParams
ClientRectsAndTexts
WebTransportDatagramStats
DecoderDoctorNotification
IntersectionObserverEntryInit
DhImportKeyParams
RTCMediaStreamStats
PermissionDescriptor
Transformer
RTCIdentityAssertion
LockManagerSnapshot
ConsoleCounterError
BasePropertyIndexedKeyframe
FontFaceSetIteratorResult
CollectedClientData
NetworkResultOptions
FakePluginTagInit
RTCIceComponentStats
ReadableStreamReadResult
Pbkdf2Params
MediaTrackSettings
ConsoleTimerStart
RsaOtherPrimesInfo
HIDCollectionInfo
DOMWindowResizeEventDetail
ProfileTimelineMarker
DhKeyGenParams
ImageDecodeResult
RsaHashedKeyGenParams
SerialPortInfo
NavigatorUABrandVersion
MemoryMeasurement
RequestMediaKeySystemAccessNotification
CheckerboardReport
LocaleInfo
RsaPssParams
VideoDecoderSupport
TreeCellInfo
AesCbcParams
RsaHashedImportParams
MemoryAttributionContainer
IterableKeyOrValueResult
ConsoleProfileEvent
RTCIceCandidateStats
MediaTrackSupportedConstraints
DNSCacheDict
FetchReadableStreamReadDataArray
RTCRTPStreamStats
BasicCardRequest
MemoryBreakdownEntry
WidevineCDMManifest
RTCRTPContributingSourceStats
XRPermissionDescriptor
DoubleRange
KeyIdsInitData
ConnStatusDict
VideoEncoderSupport
DisplayNameResult
ProfileTimelineLayerRect
RsaHashedKeyAlgorithm
RTCRtpCapabilities
ConsoleCounter
SocketElement
WebTransportStats
NativeOSFileWriteAtomicOptions
AesCtrParams
BasicCardResponse
HttpConnDict
DNSLookupDict
SocketsDict
BaseKeyframe
LockInfo
EncodedVideoChunkMetadata
ProfileTimelineStackFrame
SignResponse
RTCCodecStats
PushSubscriptionJSON
BaseComputedKeyframe
HIDReportInfo
AesGcmParams
EcKeyImportParams
AudioEncoderSupport
WebTransportReceiveStreamStats
U2FClientData
FetchReadableStreamReadDataDone
ULongRange
DnsCacheEntry
ClipboardPermissionDescriptor
UALowEntropyJSON
FakePluginMimeEntry
WebGLContextAttributes
XRSessionSupportedPermissionDescriptor
MutationObservingInfo
RTCCertificateExpiration
MediaTrackCapabilities
RTCRtpSynchronizationSource
SerialInputSignals
IterableKeyAndValueResult
AnimationPropertyDetails
HkdfParams
RTCRtpHeaderExtensionCapability
JsonWebKey
EncodedAudioChunkMetadata
BluetoothDataFilterInit
ConsoleTimerError
RTCStatsReportInternal
CryptoKeyPair
SvcOutputMetadata
AesDerivedKeyParams
NetworkCommandOptions
HttpConnectionElement
EcKeyGenParams
WebTransportSendStreamStats
OpenWindowEventDetail
KeyAlgorithm
HttpConnInfo
HmacImportParams
BluetoothPermissionStorage
DhKeyAlgorithm
HmacKeyAlgorithm
HIDReportItem
LifecycleCallbacks
MediaSessionActionDetails
DOMQuadInit
DOMMatrixInit
AuthenticationExtensionsClientOutputs
RsaOaepParams
MemoryAttribution
HalfOpenInfoDict
CacheBatchOperation
AesKeyAlgorithm
RTCTransportStats
EcKeyAlgorithm
RcwnStatus
RTCRtpContributingSource
ConsoleTimerLogOrEnd
DhKeyDeriveParams
USBPermissionDescriptor
ChromeFilePropertyBag
EcdhKeyDeriveParams
AllowedBluetoothDevice
UADataValues
RcwnPerfStats
RTCOutboundRTPStreamStats
HmacKeyGenParams
RTCIceCandidatePairStats
L10nElement
WebSocketElement
ContextAttributes2D
AudioDecoderSupport
BluetoothPermissionDescriptor
AutocompleteInfo
RegisterResponse
RTCRtpSourceEntry
RTCInboundRTPStreamStats
ConsoleEvent
ConsoleStackEntry
WebSocketDict
ComputedEffectTiming
PushSubscriptionKeys
RTCMediaStreamTrackStats
USBPermissionStorage
HmacDerivedKeyParams
RTCStats
UnderlyingSource
UnderlyingSink
NativeOSFileReadOptions
Algorithm
BlockParsingOptions
FileSystemPermissionDescriptor
AesKeyGenParams
AnimationPropertyValueDetails
StorageEstimate
AllowedUSBDevice
175 entries, I found a lot of APIs there that were just copied from Firefox but aren't probably real accessible Web APIs, its still a lot to go through.
As I mentioned in #3993 (comment), I believe we should drop this improvement entirely, unfortunately.
I guess if somebody wants to do the legwork here, what needs to be done is to go through each one of those, go to the spec and find out if really all members are always present or which ones aren't so we can mark them, e.g. like in MediaTrackSettings
.
a657d4b
to
27d3daf
Compare
I forgot to do this earlier, but cc @pablosichert @MOZGIII since you seem to be invested in this. |
51d56ef
to
0c4e8dc
Compare
crates/webidl/src/lib.rs
Outdated
let return_ty = | ||
optional_return_ty(idl_type.to_syn_type(TypePosition::Return).unwrap().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.
Also deprecated/removed their constructors, e.g. otherwise you can just write
EffectTiming::new().get_fill()
and it would fail.
In the long-term, it might make sense to take all the fields as arguments to new
the same as regular required
fields. For the moment though, I'm not sure if there's enough need to construct return-only dictionaries to warrant adding a second constructor (which would have to be named something awkward like new2
), and we could always add it later.
Actually, I just realized, that there should be a ton of dictionaries returned from
readonly attribute
s that would fall into this category as well. Additionally, dictionaries can be wrapped inPromise
orsequence
that we didn't consider here as well.
Good point, I didn't think of that.
Ideally we should programmatically detect dictionaries that are never used as a parameter?
Yeah, that would be better.
Sorry for being late, but this looks great! |
When will this be released? |
Agree, thanks a lot @daxpedda for getting this over the finish line. I think you struck a good balance of at least deprecating the non- |
I'm going through my |
This introduces getters for all WebIDL dictionary types with the signature
get_field(&self) -> Option<Type>
.This is unconventional for Rust as usually getters are called just
field()
and setters are calledset_field()
, unfortunately we can only do this in the future with a breaking change.I also went ahead and deprecated the builder-pattern style setters in favor of exposing our currently already generated setters.
Replaces #3933.
Fixes #1793.