Skip to content

Instantly share code, notes, and snippets.

@JamesTheAwesomeDude
Last active March 28, 2024 20:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JamesTheAwesomeDude/4f7565a071aa03229d212ddcd6252d40 to your computer and use it in GitHub Desktop.
Save JamesTheAwesomeDude/4f7565a071aa03229d212ddcd6252d40 to your computer and use it in GitHub Desktop.
Javascript recursively get all transferables from object
// This is also a demonstration of the Z-combinator.
// h/t https://thenewobjective.com/types-and-programming-languages/deriving-the-z-combinator
const Z = (f => (u => f((...x) => u(u)(...x)))(u => f((...x) => u(u)(...x))));
/* Example usage:
a = new MessageChannel().port1;
b = new ArrayBuffer(42);
my_obj = {a, x: {b, a_again: a}}
get_transferables(my_obj);
*/
var get_transferables = Z(f => (
obj,
t=(Object.assign(
(
[ /* https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Transferable_objects#supported_objects */
'ArrayBuffer',
'MessagePort',
'ReadableStream',
'WritableStream',
'TransformStream',
'WebTransportReceiveStream',
'WebTransportSendStream',
'AudioData',
'ImageBitmap',
'VideoFrame',
'OffscreenCanvas',
'RTCDataChannel',
]
.map((()=>{
"use strict";
if (!(this))
throw new InternalError();
return (clsName => this[clsName]);
})())
.filter(cls => cls)
),
{
[Symbol.hasInstance](obj) {
return this.some(cls => obj instanceof cls);
}
}
)),
acc=null
) => {
acc = acc || new WeakSet();
if (typeof obj !== 'object') {
// 1. Dead Leaf
return [];
} else if (obj instanceof t) {
// 2. Transferable Leaf
if (!acc.has(obj))
// 2a. New Leaf
return [obj, ...f(obj, t, acc.add(obj))];
else
// 2a. Duplicate or ignored Leaf
return [];
} else {
// 3. Branch
return Object.entries(obj).flatMap(
([,obj_]) => f(obj_, t, acc) // FIXME this requires mutation of acc
);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment