Skip to content

Commit 49fcae9

Browse files
committed
Enable callback evaluation for boxed IConvertible sequences aswell
1 parent 66ba10d commit 49fcae9

File tree

3 files changed

+48
-4
lines changed

3 files changed

+48
-4
lines changed

Diff for: dev/Program.fs

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ let callbackArrayInput =
7474
],
7575
(fun (inputs:float []) (nclicks:float) ->
7676
[
77-
"output-1" @. Children => (Array.last inputs) * nclicks * 1.
78-
"output-2" @. Children => (Array.last inputs) * nclicks * 2.
77+
(Array.last inputs) * nclicks * 1.
78+
(Array.last inputs) * nclicks * 2.
7979
]
8080
),
8181
State = [

Diff for: src/Dash.NET/Callback.fs

+29-2
Original file line numberDiff line numberDiff line change
@@ -367,9 +367,12 @@ type Callback<'Function>
367367

368368
match r with
369369
| :? seq<CallbackResultBinding> as bindings ->
370+
// The result is a sequence of boxed CallbackResultBindings
371+
370372
CallbackResponse.multiOut(bindings)
371373

372374
| :? seq<obj> as boxedResults ->
375+
// The result of the multioutput is a sequence of boxed types
373376

374377
let outputs =
375378
handler?outputDependencies
@@ -381,13 +384,37 @@ type Callback<'Function>
381384
outputs
382385
|> Seq.zip boxedResults
383386
|> Seq.map (fun (boxedRes, output) -> output.Id, output.Property, boxedRes)
384-
385387
)
386388

387389
else
388390
failwithf "amount of multi callback outputs did not match to the actual callback binding (expected %i but got %i)" (Seq.length outputs) (Seq.length boxedResults)
389391

390-
| _ -> failwithf "multi callback result %O was not a collection." r
392+
| r when (isIConvertibleSeq (r.GetType())) ->
393+
// The result of the multioutput is a boxed sequence of IConvertibles, e.g.
394+
// [2;3;4], [|"1";"2"|]; seq{2.;3.}
395+
396+
let primitiveSeq =
397+
r
398+
|> unbox<System.Collections.IEnumerable>
399+
|> Seq.cast<IConvertible>
400+
401+
let outputs =
402+
handler?outputDependencies
403+
|> unbox<seq<CallbackOutput>>
404+
405+
if (Seq.length outputs) = (Seq.length primitiveSeq) then
406+
407+
CallbackResponse.multiOut(
408+
outputs
409+
|> Seq.zip primitiveSeq
410+
|> Seq.map (fun (result, output) -> output.Id, output.Property, (box result))
411+
412+
)
413+
414+
else
415+
failwithf "The amount of multi callback outputs returned by the callback function did not match to the amount of outputs defined by the callback dependency (expected %i vs %i). Make sure that the callback function returns a collection of results of length %i" (Seq.length primitiveSeq) (Seq.length outputs) (Seq.length outputs)
416+
417+
| _ -> failwithf "multi callback result %O of type %O was not a supported collection (supported: seq<IConvertible>, seq<obj>, seq<CallbackResultBinding>). You might be able to circumvent this problem by boxing the return values of your results to generate a seq<obj>." r (r.GetType())
391418

392419
else
393420

Diff for: src/Dash.NET/DynamicInvoke.fs

+17
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,23 @@ module DynamicInvoke =
3131
f
3232
loop t
3333

34+
let isIConvertible (t:Type) =
35+
t.GetInterfaces()
36+
|> Array.exists (fun t -> t = typeof<IConvertible>)
37+
38+
let isSeq (t:Type) =
39+
t.GetInterfaces()
40+
|> Array.exists (fun t -> t = typeof<System.Collections.IEnumerable>)
41+
42+
let isIConvertibleSeq (t:Type) =
43+
if isSeq t then
44+
let genericArgs = t.GetGenericArguments()
45+
if genericArgs.Length > 0 then
46+
isIConvertible genericArgs.[0]
47+
else
48+
false
49+
else
50+
false
3451

3552
//This function is (as far as i see it) a 'necessary evil' for solving the problem of callbacks having arbitrary amounts of parameters.
3653
//However, just like DynamicObj in Plotly.NET, it is definately usable when correctly encapsulated to prevent direct usage.

0 commit comments

Comments
 (0)