Skip to content

Use opaque types for Scala 3 #592

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

Merged
merged 4 commits into from
Oct 17, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/main/scala-3/org/scalajs/dom/ClientType.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.scalajs.dom

import scala.scalajs.js

opaque type ClientType = String

object ClientType {
val window: ClientType = "window"

val worker: ClientType = "worker"

val sharedworker: ClientType = "sharedworker"

val all: ClientType = "all"
}
23 changes: 23 additions & 0 deletions src/main/scala-3/org/scalajs/dom/FrameType.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.scalajs.dom

import scala.scalajs.js

opaque type FrameType = String

/** part of ServiceWorker
* [[https://slightlyoff.github.io/ServiceWorker/spec/service_worker_1/#client-frametype ¶4.2.2 frameType]] of
* serviceWorker spec
*/
object FrameType {

/** The window client's global object's browsing context is an auxiliary browsing context. */
val auxiliary: FrameType = "auxiliary"

/** The window client's global object's browsing context is a top-level browsing context. */
val `top-level`: FrameType = "top-level"

/** The window client's global object's browsing context is a nested browsing context. */
val nested: FrameType = "nested"

val none: FrameType = "none"
}
34 changes: 34 additions & 0 deletions src/main/scala-3/org/scalajs/dom/IDBCursorDirection.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/** All documentation for facades is thanks to Mozilla Contributors at https://developer.mozilla.org/en-US/docs/Web/API
* and available under the Creative Commons Attribution-ShareAlike v2.5 or later.
* http://creativecommons.org/licenses/by-sa/2.5/
*
* Everything else is under the MIT License http://opensource.org/licenses/MIT
*/
package org.scalajs.dom

import scala.scalajs.js

opaque type IDBCursorDirection = js.Any

object IDBCursorDirection {

/** The cursor shows all records, including duplicates. It starts at the upper bound of the key range and moves
* downwards (monotonically decreasing in the order of keys).
*/
@inline def prev: IDBCursorDirection = "prev"

/** The cursor shows all records, excluding duplicates. If multiple records exist with the same key, only the first
* one iterated is retrieved. It starts at the upper bound of the key range and moves downwards.
*/
@inline def prevunique: IDBCursorDirection = "prevunique"

/** The cursor shows all records, including duplicates. It starts at the lower bound of the key range and moves
* upwards (monotonically increasing in the order of keys).
*/
@inline def next: IDBCursorDirection = "next"

/** The cursor shows all records, excluding duplicates. If multiple records exist with the same key, only the first
* one iterated is retrieved. It starts at the lower bound of the key range and moves upwards.
*/
@inline def nextunique: IDBCursorDirection = "nextunique"
}
17 changes: 17 additions & 0 deletions src/main/scala-3/org/scalajs/dom/IDBTransactionDurability.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/** All documentation for facades is thanks to Mozilla Contributors at https://developer.mozilla.org/en-US/docs/Web/API
* and available under the Creative Commons Attribution-ShareAlike v2.5 or later.
* http://creativecommons.org/licenses/by-sa/2.5/
*
* Everything else is under the MIT License http://opensource.org/licenses/MIT
*/
package org.scalajs.dom

import scala.scalajs.js

opaque type IDBTransactionDurability = String

object IDBTransactionDurability {
@inline def default: IDBTransactionDurability = "default"
@inline def strict: IDBTransactionDurability = "strict"
@inline def relaxed: IDBTransactionDurability = "relaxed"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason for some of the constants to be @inline defs instead of vals? It seems that it would be nicer if all of them were vals, doesn't it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I'll take a pass through and clean these up.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah that's me, or if it wasn't me, that's something I do. My reasoning is that it reduces unnecessary bytecode. If they're vals they're always present in the output JS (so long as the object is instantiated), where as with defs unused fields can be omitted.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that's a good point. I think the advantage of vals is that they are stable and can be used for matching, but not sure how much use that is here. Happy to go either way.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way these get inlined e.g. if they are final val?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw: just noting that if a future release of Scala.js gets some kind of purity checking it will be able to remove unused vals from the output too. It wouldn't even need to be complex to detect cases like this. @sjrd: I'm might just ping to put it back on your radar :)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you used inline val you would also end up with no field in the bytecode.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to know, can we still make this change binary-compatibly?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know well enough how binary-compatibility works in the Scala.js world so I can't say :).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know well enough the behavior of inline val in terms of compilation scheme so I can't say :).

We'll have to try.

}
29 changes: 29 additions & 0 deletions src/main/scala-3/org/scalajs/dom/IDBTransactionMode.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/** All documentation for facades is thanks to Mozilla Contributors at https://developer.mozilla.org/en-US/docs/Web/API
* and available under the Creative Commons Attribution-ShareAlike v2.5 or later.
* http://creativecommons.org/licenses/by-sa/2.5/
*
* Everything else is under the MIT License http://opensource.org/licenses/MIT
*/
package org.scalajs.dom

import scala.scalajs.js

/** IndexedDB transaction mode Provides constants for IDB Transaction modes These constants have been removed from
* browser support and replaced by String values
*/
opaque type IDBTransactionMode = String

object IDBTransactionMode {

/** Allows data to be read but not changed. It is the default transaction mode. */
@inline def readonly: IDBTransactionMode = "readonly"

/** Allows any operation to be performed, including ones that delete and create object stores and indexes. This mode
* is for updating the version number of transactions that were started using the setVersion() method of IDBDatabase
* objects. Transactions of this mode cannot run concurrently with other transactions.
*/
@inline def versionchange: IDBTransactionMode = "versionchange"

/** Allows reading and writing of data in existing data stores to be changed. */
@inline def readwrite: IDBTransactionMode = "readwrite"
}
21 changes: 21 additions & 0 deletions src/main/scala-3/org/scalajs/dom/KeyFormat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.scalajs.dom

import scala.scalajs.js

/** see [[http://www.w3.org/TR/WebCryptoAPI/#dfn-KeyFormat ¶14.2 Data Types]] in W3C spec */
opaque type KeyFormat = String

object KeyFormat {

/** An unformatted sequence of bytes. Intended for secret keys. */
val raw: KeyFormat = "raw"

/** The DER encoding of the PrivateKeyInfo structure from RFC 5208. */
val pkcs8: KeyFormat = "pkcs8"

/** The DER encoding of the SubjectPublicKeyInfo structure from RFC 5280. */
val spki: KeyFormat = "spki"

/** The key is a JsonWebKey dictionary encoded as a JavaScript object */
val jwk: KeyFormat = "jwk"
}
12 changes: 12 additions & 0 deletions src/main/scala-3/org/scalajs/dom/KeyType.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.scalajs.dom

import scala.scalajs.js

/** see [[http://www.w3.org/TR/WebCryptoAPI/#cryptokey-interface ¶13 CryptoKey interface]] in W3C doc */
opaque type KeyType = String

object KeyType {
val public: KeyType = "public"
val `private`: KeyType = "private"
val secret: KeyType = "secret"
}
17 changes: 17 additions & 0 deletions src/main/scala-3/org/scalajs/dom/KeyUsage.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.scalajs.dom

import scala.scalajs.js

/** See [[http://www.w3.org/TR/WebCryptoAPI/#cryptokey-interface ¶ 13. CryptoKey Interface]] of w3c spec */
opaque type KeyUsage = String

object KeyUsage {
val encrypt: KeyUsage = "encrypt"
val decrypt: KeyUsage = "decrypt"
val sign: KeyUsage = "sign"
val verify: KeyUsage = "verify"
val deriveKey: KeyUsage = "deriveKey"
val deriveBits: KeyUsage = "deriveBits"
val wrapKey: KeyUsage = "wrapKey"
val unwrapKey: KeyUsage = "unwrapKey"
}
15 changes: 15 additions & 0 deletions src/main/scala-3/org/scalajs/dom/MIMEType.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.scalajs.dom

import scala.scalajs.js

opaque type MIMEType = String

object MIMEType {
val `text/html`: MIMEType = "text/html"
val `text/xml`: MIMEType = "text/xml"
val `application/xml`: MIMEType = "application/xml"

val `application/xhtml+xml`: MIMEType =
"application/xhtml+xml"
val `image/svg+xml`: MIMEType = "image/svg+xml"
}
19 changes: 19 additions & 0 deletions src/main/scala-3/org/scalajs/dom/MediaDeviceKind.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/** https://www.w3.org/TR/2016/CR-mediacapture-streams-20160519/ */
package org.scalajs.dom

import scala.scalajs.js

/** see [[https://www.w3.org/TR/2016/CR-mediacapture-streams-20160519/#idl-def-MediaDeviceKind]] in W3C spec */
opaque type MediaDeviceKind = String

object MediaDeviceKind {

/** Represents an audio input device; for example a microphone. */
val audioinput: MediaDeviceKind = "audioinput"

/** Represents an audio output device; for example a pair of headphones. */
val audiooutput: MediaDeviceKind = "audiooutput"

/** Represents a video input device; for example a webcam. */
val videoinput: MediaDeviceKind = "videoinput"
}
23 changes: 23 additions & 0 deletions src/main/scala-3/org/scalajs/dom/MediaStreamTrackState.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/** https://www.w3.org/TR/2016/CR-mediacapture-streams-20160519/ */
package org.scalajs.dom

import scala.scalajs.js

/** see [[https://www.w3.org/TR/2013/WD-mediacapture-streams-20130903/#widl-MediaStream-onended]] in W3C spec */
opaque type MediaStreamTrackState = String

object MediaStreamTrackState {

/** The track is active (the track's underlying media source is making a best-effort attempt to provide data in real
* time). The output of a track in the live state can be switched on and off with the enabled attribute.
*/
val live: MediaStreamTrackState = "live"

/** The track has ended (the track's underlying media source is no longer providing data, and will never provide more
* data for this track). Once a track enters this state, it never exits it.
*
* For example, a video track in a MediaStream ends if the user unplugs the USB web camera that acts as the track's
* media source.
*/
val ended: MediaStreamTrackState = "ended"
}
15 changes: 15 additions & 0 deletions src/main/scala-3/org/scalajs/dom/PermissionName.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.scalajs.dom

import scala.scalajs.js

opaque type PermissionName = String

object PermissionName {
val geolocation: PermissionName = "geolocation"
val midi: PermissionName = "midi"
val notifications: PermissionName = "notifications"
val push: PermissionName = "push"

val `persistent-storage`: PermissionName =
"persistent-storage"
}
11 changes: 11 additions & 0 deletions src/main/scala-3/org/scalajs/dom/PermissionState.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.scalajs.dom

import scala.scalajs.js

opaque type PermissionState = String

object PermissionState {
val granted: PermissionState = "granted"
val denied: PermissionState = "denied"
val prompt: PermissionState = "prompt"
}
22 changes: 22 additions & 0 deletions src/main/scala-3/org/scalajs/dom/PushEncryptionKeyName.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.scalajs.dom

import scala.scalajs.js

/** This represents a JavaScript enumeration representing the various keys you an request from a [[PushSubscription]] as
* described here: [[http://www.w3.org/TR/push-api/#idl-def-PushEncryptionKeyName]]
*/
opaque type PushEncryptionKeyName = String

/** Static definitions for [[PushEncryptionKeyName]] */
object PushEncryptionKeyName {

/** used to retrieve the P-256 ECDH Diffie-Hellman public key described here:
* [[https://tools.ietf.org/html/draft-ietf-webpush-encryption-01]]
*/
val p256dh: PushEncryptionKeyName = "p256dh"

/** used to retrieve the authentication secret described here:
* [[https://tools.ietf.org/html/draft-ietf-webpush-encryption-01]]
*/
val auth: PushEncryptionKeyName = "auth"
}
21 changes: 21 additions & 0 deletions src/main/scala-3/org/scalajs/dom/PushPermissionState.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.scalajs.dom

import scala.scalajs.js

/** This represents a JavaScript enumeration describing the state of permissions for pushing described here:
* [[http://www.w3.org/TR/push-api/#idl-def-PushPermissionState]]
*/
opaque type PushPermissionState = String

/** Static definitions for [[PushPermissionState]] */
object PushPermissionState {

/** The webapp has permission to use the Push API. */
val granted: PushPermissionState = "granted"

/** The webapp has been denied permission to use the Push API. */
val denied: PushPermissionState = "denied"

/** The webapp needs to ask for permission in order to use the Push API. */
val prompt: PushPermissionState = "prompt"
}
25 changes: 25 additions & 0 deletions src/main/scala-3/org/scalajs/dom/RTCBundlePolicy.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/** http://www.w3.org/TR/2015/WD-webrtc-20150210/ */
package org.scalajs.dom

import scala.scalajs.js

/** see [[https://www.w3.org/TR/2015/WD-webrtc-20150210/#idl-def-RTCBundlePolicy]] in W3C spec */
opaque type RTCBundlePolicy = String

object RTCBundlePolicy {

/** Gather ICE candidates for each media type in use (audio, video, and data). If the remote endpoint is not
* BUNDLE-aware, negotiate only one audio and video track on separate transports.
*/
val balanced: RTCBundlePolicy = "balanced"

/** Gather ICE candidates for each track. If the remote endpoint is not BUNDLE-aware, negotiate all media tracks on
* separate transports.
*/
val `max-compat`: RTCBundlePolicy = "max-compat"

/** Gather ICE candidates for only one track. If the remote endpoint is not BUNDLE-aware, negotiate only one media
* track.
*/
val `max-bundle`: RTCBundlePolicy = "max-bundle"
}
26 changes: 26 additions & 0 deletions src/main/scala-3/org/scalajs/dom/RTCDataChannelState.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/** http://www.w3.org/TR/2015/WD-webrtc-20150210/ */
package org.scalajs.dom

import scala.scalajs.js

/** see [[https://www.w3.org/TR/2015/WD-webrtc-20150210/#idl-def-RTCDataChannelState]] in W3C spec */
opaque type RTCDataChannelState = String

object RTCDataChannelState {

/** The user agent is attempting to establish the underlying data transport. This is the initial state of a
* RTCDataChannel object created with createDataChannel().
*/
val connecting: RTCDataChannelState = "connecting"

/** The underlying data transport is established and communication is possible. This is the initial state of a
* RTCDataChannel object dispatched as a part of a RTCDataChannelEvent.
*/
val open: RTCDataChannelState = "open"

/** The procedure to close down the underlying data transport has started. */
val closing: RTCDataChannelState = "closing"

/** The underlying data transport has been closed or could not be established. */
val closed: RTCDataChannelState = "closed"
}
Loading