stefan-hoeck/idris2-dom

No way to trigger a `fetch`

gergoerdi opened this issue · 17 comments

In Web.Raw.Fetch, there are lots of methods operating on Requests and Responses, but I haven't found a way to actually initiate a Request. I think this would need the following new functions:

%foreign "browser:lambda:r => fetch(r)"
prim__fetch : Union2 String Request -> PrimIO (Promise Response)

raw__fetch : NS I [String, Request] -> JSIO (Promise Response)
raw__fetch = primIO . prim__fetch . toUnion2

export
fetch : {auto prf : Elem a [String, Request]} -> a -> JSIO (Promise Response)
fetch {prf = prf} x = raw__fetch $ inject {prf = prf} x

Also I believe some Cast instances are needed for ArrayBuffer to be able to work with it at various word sizes, e.g.;

%foreign "javascript:lambda:x => new Uint8Array(x)"
prim__toUint8Array : ArrayBuffer -> UInt8Array

Cast ArrayBuffer UInt8Array where
  cast = prim__toUint8Array

In Web.Raw.Fetch, there are lots of methods operating on Requests and Responses, but I haven't found a way to actually initiate a Request. I think this would need the following new functions:

%foreign "browser:lambda:r => fetch(r)"
prim__fetch : Union2 String Request -> PrimIO (Promise Response)

raw__fetch : NS I [String, Request] -> JSIO (Promise Response)
raw__fetch = primIO . prim__fetch . toUnion2

export
fetch : {auto prf : Elem a [String, Request]} -> a -> JSIO (Promise Response)
fetch {prf = prf} x = raw__fetch $ inject {prf = prf} x

I'll have a look at this later today.

Also I believe some Cast instances are needed for ArrayBuffer to be able to work with it at various word sizes, e.g.;

%foreign "javascript:lambda:x => new Uint8Array(x)"
prim__toUint8Array : ArrayBuffer -> UInt8Array

Cast ArrayBuffer UInt8Array where
  cast = prim__toUint8Array

I'm not sure about this one: Are ArrayBuffer and Uint8Array immutable? Otherwise, prim__toUint8Array is not referentially transparent.

I'm not sure about this one: Are ArrayBuffer and Uint8Array immutable? Otherwise, prim__toUint8Array is not referentially transparent.

I think you're making the mistake of thinking Javascript is a sane language :)

Yes, typed arrays like Uint8Array are mutable. However, when you make a new Uint8Array(arrayBuffer), the typed array is sharing the underlying storage with both the original ArrayBuffer as well as any other typed arrays created from it.

Here's an example session in the Chrome webdev console:

> var buf;
> fetch("hello.ipkg").then((x) => x.arrayBuffer()).then((x) => buf = x);
> var arr8 = new Uint8Array(buf);
> var arr16 = new Uint16Array(buf);
> arr8[0] // First to bytes when accessed via Uint8Array
< 112
> arr8[1]
< 97
> arr16[0] // First two-byte word when accessed via Uint16Array
< 24944
> arr8[0] = 255 // Change first byte via Uint8Array
< 255
> arr16[0] // First two-byte word of Uint16Array changed!
< 25087
> new Uint8Array(buf)[0] // We can create a fresh `Uint8Array` from the buffer and it still points to same data
< 255

So based on this, I'd argue the Cast instance is kosher.

(do you have some nice admin way of splitting this into two issues? I think the ArrayBuffer one should probably be a separate issue but it'd be nice to keep the comments so far)

(do you have some nice admin way of splitting this into two issues? I think the ArrayBuffer one should probably be a separate issue but it'd be nice to keep the comments so far)

Don't know, whether this is possible. I think I'll just change the title of the issue once I got around implementing the fetch stuff.

I think you're making the mistake of thinking Javascript is a sane language :)

Probably :-). But then I wouldn't wrap all my functions in JSIO, would I?

Yes, typed arrays like Uint8Array are mutable. However, when you make a new Uint8Array(arrayBuffer), the typed array is sharing the underlying storage with both the original ArrayBuffer as well as any other typed arrays created from it.

Question is: Is this part of the specification and all JS runtimes work like this (Node and all Browsers), or is this an implementation detail, in which case the Cast instance would be invalid.

No, this really is how typed arrays are supposed to work, if I am reading the spec right: quoting section 23.2 of the ECMAScript spec (emphasis mine):

A TypedArray presents an array-like view of an underlying binary data buffer (25.1).

Great! Thanks for looking this up. In that case we should indeed be fine. I'll try to add this in the next couple of days. Feel free to write a PR yourself if you find the time to do so.

Now back to the original issue: I see that the IDL already contains the fetch method but the generated Idris2 source doesn't. So is this something that should really be handled in idris2-webidl?

Now back to the original issue: I see that the IDL already contains the fetch method but the generated Idris2 source doesn't. So is this something that should really be handled in idris2-webidl?

Yes, definitely! I'll have a look why idris2-webidl does not generate the bindings for fetch automatically.

I think this can be closed as both issues have been fixed, right?

Have they? I still don't see a way to actually execute a fetch in the latest version of idris2-dom.

Sorry, I though it was part of one of your PRs.

@stefan-hoeck: Should we create a new ticket at the Github-repository of idris2-webidl concerning this? Because that's where a fix is needed, right?

Also, I still don't understand why idris2-webidl does not generate bindings for fetch. What's the specific reason? A certain feature idris2-webidl is lacking?

@stefan-hoeck: Should we create a new ticket at the Github-repository of idris2-webidl concerning this? Because that's where a fix is needed, right?

Also, I still don't understand why idris2-webidl does not generate bindings for fetch. What's the specific reason? A certain feature idris2-webidl is lacking?

Yes, please open a ticket there. idris2-webidl does not generate those bindings, because I have not yet added the corresponding webidl files to it. That's the only reason.

I think this can be closed now.