Skip to content

Commit caa96b5

Browse files
committed
type stability and compile time improvements
1 parent 8dc738b commit caa96b5

File tree

8 files changed

+55
-60
lines changed

8 files changed

+55
-60
lines changed

src/asset.jl

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ specified if nonstandard extensions are in use.
2323
"""
2424
struct Asset
2525
filetype::String
26-
name::Union{Nothing, String}
26+
name::String
2727
url::String
2828
end
2929

3030
Asset(name, url) = Asset(getextension(url), name, url)
31-
Asset(url) = Asset(nothing, url)
31+
Asset(url) = Asset("", url)
3232
Asset(x::Pair) = Asset(string(x[1]), x[2])
3333
Asset(x::Asset) = x
3434
function Asset(spec::Dict)
@@ -42,23 +42,21 @@ function Asset(spec::Dict)
4242
error("Invalid Asset dict specification: missing key \"url\".")
4343
end
4444
filetype = get(spec, "type", getextension(url))
45-
name = get(spec, "name", nothing)
45+
name = get(spec, "name", "")
4646

4747
return Asset(filetype, name, url)
4848
end
4949

5050
function JSON.lower(asset::Asset)
51-
Dict(
52-
"type" => asset.filetype,
53-
"url" => dep2url(asset.url),
54-
"name" => asset.name,
55-
)
51+
(type=asset.filetype, url=dep2url(asset.url), name=asset.name,)
5652
end
5753

5854

5955
function tojs(asset::Asset)
60-
return js"WebIO.importResource($(JSON.lower(asset)))"
56+
la = JSON.lower(asset)
57+
return _assettojs(la)
6158
end
59+
_assettojs(la) = js"WebIO.importResource($la)"
6260

6361
"""
6462
Sync(assets...)
@@ -79,12 +77,12 @@ julia> WebIO.Sync(Asset("foo.js"), "bar" => "bar.js")
7977
Sync(Asset[Asset("js", nothing, "foo.js"), Asset("js", "bar", "bar.js")])
8078
```
8179
"""
82-
struct Sync
83-
# This is untyped because we can't define a union type that includes all of
84-
# Asset, Sync, and Async that is then used within Sync and Async.
85-
imports::Array{Any}
86-
87-
Sync(imports::Array) = new([ensure_asset(asset) for asset in imports])
80+
struct Sync{A<:Array}
81+
imports::A
82+
Sync(imports::A) where A<:Array = begin
83+
assets = [ensure_asset(asset) for asset in imports]
84+
new{typeof(assets)}(assets)
85+
end
8886
end
8987
Sync(assets...) = Sync([assets...])
9088

@@ -99,32 +97,31 @@ constructor for an [`Asset`](@ref), or a [`Sync`](@ref) or [`Async`](@ref).
9997
10098
If the imports need to be imported sequentially, use [`Sync`](@ref) instead.
10199
"""
102-
struct Async
103-
# See comment about (lack of) typing in Sync above.
104-
imports::Array{Any}
100+
struct Async{A<:Array}
101+
imports::A
105102

106-
Async(imports::Array) = new([ensure_asset(asset) for asset in imports])
103+
function Async(imports::A) where A<:Array
104+
assets = [ensure_asset(asset) for asset in imports]
105+
new{typeof(assets)}(assets)
106+
end
107107
end
108108
Async(assets...) = Async([assets...])
109109

110110
# This allows js"await $(Async([....]))" on a tree of assets!
111111
function tojs(asset::Union{Async,Sync})
112-
return js"WebIO.importBlock($(lowerassets(asset)))"
112+
lowered = lowerassets(asset)
113+
return _synctojs(lowered)
113114
end
115+
# Function barrier
116+
_synctojs(la) = js"WebIO.importBlock($la)"
114117

115118
# The output of lowerassets is initially sent with the Scope
116119
# this should trigger loading of the assets before onmount callbacks
117120
lowerassets(x) = JSON.lower(Asset(x))
118121
lowerassets(x::Asset) = JSON.lower(x)
119-
lowerassets(x::Async) = Dict(
120-
"type" => "async_block",
121-
"data" => map(lowerassets, x.imports),
122-
)
122+
lowerassets(x::Async) = (type="async_block", data=map(lowerassets, x.imports))
123123
lowerassets(x::AbstractArray) = lowerassets(Async(x))
124-
lowerassets(x::Sync) = Dict(
125-
"type"=>"sync_block",
126-
"data" => map(lowerassets, x.imports),
127-
)
124+
lowerassets(x::Sync) = (type="sync_block", data=map(lowerassets, x.imports))
128125

129126
"""
130127
ensure_asset(asset)

src/iframe.jl

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
export iframe
22

33
mutable struct IFrame
4-
innerHTML::AbstractString
5-
bundleURL::AbstractString
4+
innerHTML::String
5+
bundleURL::String
66
end
77

8-
iframe_bundle_key() = AssetRegistry.register(normpath(joinpath(
9-
GENERIC_HTTP_BUNDLE_PATH
10-
)))
8+
iframe_bundle_key() = AssetRegistry.register(normpath(joinpath(GENERIC_HTTP_BUNDLE_PATH)))
119

1210
"""
1311
iframe(content)
@@ -30,7 +28,7 @@ function iframe(content)
3028
dom = node(
3129
:div,
3230
node(ifr),
33-
style=Dict(
31+
style=Dict{Symbol,String}(
3432
:display => "inherit",
3533
:margin => "inherit",
3634
),

src/node.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ struct Node{T}
4343
end
4444

4545
function Node(instanceof, children...; props...)
46-
return Node(instanceof, collect(Any, children), Dict(props...))
46+
return Node(instanceof, collect(Any, children), Dict{Symbol,Any}(props...))
4747
end
4848

4949
# Can/should this be deprecated?

src/observable.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using JSON
22

33
struct ObservableNode
4-
id::AbstractString
5-
name::AbstractString
4+
id::String
5+
name::String
66
end

src/rpc.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ registered_rpcs = Dict{UInt, Function}()
55
function tojs(f::Function)
66
h = hash(f)
77
registered_rpcs[h] = f
8-
return js"WebIO.getRPC($(string(h)))"
8+
return JSString("WebIO.getRPC($(string(h)))")
99
end
1010

1111
"""

src/scope.jl

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import Sockets: send
1818
import Observables: Observable, AbstractObservable, listeners
1919

2020
# bool marks if it is synced
21-
const ObsDict = Dict{String, Tuple{AbstractObservable, Union{Nothing,Bool}}}
21+
const ObsDict = Dict{String, Tuple{Observable, Union{Nothing,Bool}}}
2222

2323
mutable struct Scope
2424
dom::Any
@@ -33,7 +33,7 @@ mutable struct Scope
3333
# "observable-name" => ["array", "of", "JS", "strings"]
3434
# where each JS-string is a function that is invoked when the observable
3535
# changes.
36-
jshandlers::Any
36+
jshandlers::Dict{String,Any}
3737
pool::ConnectionPool
3838

3939
mount_callbacks::Vector{JSString}
@@ -44,7 +44,7 @@ mutable struct Scope
4444
private_obs::Set{String},
4545
systemjs_options::Any,
4646
imports::Vector{Asset},
47-
jshandlers::Any,
47+
jshandlers::Dict{String,Any},
4848
pool::ConnectionPool,
4949
mount_callbacks::Vector{JSString}
5050
)
@@ -124,7 +124,7 @@ function Scope(;
124124
private_obs::Set{String} = Set{String}(),
125125
systemjs_options = nothing,
126126
imports = Asset[],
127-
jshandlers::Dict = Dict(),
127+
jshandlers::Dict = Dict{String,Any}(),
128128
mount_callbacks::Vector{JSString} = JSString[],
129129
# Deprecated
130130
id=nothing,
@@ -233,7 +233,7 @@ function Observable(ctx::Scope, key, val::T; sync=nothing) where {T}
233233
end
234234

235235
function JSON.lower(scope::Scope)
236-
obs_dict = Dict()
236+
obs_dict = Dict{String,Dict{String,Any}}()
237237
for (k, ob_) in scope.observs
238238
ob, sync = ob_
239239
if k in scope.private_obs
@@ -244,13 +244,13 @@ function JSON.lower(scope::Scope)
244244
# other than the JS back edge
245245
sync = any(f-> !isa(f, SyncCallback), listeners(ob))
246246
end
247-
obs_dict[k] = Dict(
247+
obs_dict[k] = Dict{String,Any}(
248248
"sync" => sync,
249249
"value" => ob[],
250250
"id" => obsid(ob)
251251
)
252252
end
253-
Dict(
253+
Dict{String,Any}(
254254
"id" => scopeid(scope),
255255
"systemjs_options" => scope.systemjs_options,
256256
"imports" => lowerassets(scope.imports),
@@ -310,12 +310,12 @@ function onmount(scope::Scope, f::JSString)
310310
end
311311

312312
function onimport(scope::Scope, f::JSString)
313-
onmount(scope, js"""
313+
onmount(scope, JSString("""
314314
function () {
315-
var handler = ($(f));
316-
($(Async(scope.imports))).then((imports) => handler.apply(this, imports));
315+
var handler = ($f);
316+
($(tojs(Async(scope.imports)))).then((imports) => handler.apply(this, imports));
317317
}
318-
""")
318+
"""))
319319
end
320320

321321
onmount(scope::Scope, f) = onmount(scope, JSString(f))
@@ -326,9 +326,9 @@ Base.@deprecate ondependencies(ctx, jsf) onimport(ctx, jsf)
326326
"""
327327
A callable which updates the frontend
328328
"""
329-
struct SyncCallback
330-
ctx
331-
f
329+
struct SyncCallback{C,F}
330+
ctx::C
331+
f::F
332332
end
333333

334334
(s::SyncCallback)(xs...) = s.f(xs...)

src/syntax.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ function cssparse(s)
77
# e.g. s = "img#theid.class1.class2[src=image.jpg, alt=great pic]"
88
# parse props first
99
p = match(r"\[[^\]]+\]", s)
10-
props = Dict()
10+
props = Dict{Symbol,Any}()
1111
if p != nothing
1212
m = strip(p.match, ['[',']'])
1313
props[:attributes] = Dict(map(x->Pair(split(x,r"\s*=\s*", limit=2)...), split(m, r",\s*")))
@@ -207,7 +207,7 @@ const myStr = "foo"; const myObject = {"spam":"eggs","foo":"bar"};
207207
"""
208208
macro js_str(s)
209209
writes = map(Interpolator(s)) do x
210-
if isa(x, AbstractString)
210+
if x isa AbstractString
211211
# If x is a string, it was specified in the js"..." literal so let it
212212
# through as-is.
213213
:(write(io, $(x)))

test/asset.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,33 +46,33 @@ using Test
4646

4747
@testset "Sync constructor" begin
4848
single = Sync("foo.js")
49-
@test typeof(single) === Sync
49+
@test typeof(single) === Sync{Vector{Asset}}
5050
@test single.imports[1] == Asset("foo.js")
5151

5252
double = Sync("foo" => "foo.js", Asset("bar.css"))
53-
@test typeof(double) === Sync
53+
@test typeof(double) === Sync{Vector{Asset}}
5454
@test double.imports[1] == Asset("foo" => "foo.js")
5555
@test double.imports[2] == Asset("bar.css")
5656

5757
nested = Sync(Sync("stepone.js", "steptwo.js"), "bar.css")
58-
@test typeof(nested) === Sync
58+
@test typeof(nested) === Sync{Vector{Any}}
5959
@test nested.imports[1].imports[1] == Asset("stepone.js")
6060
@test nested.imports[1].imports[2] == Asset("steptwo.js")
6161
@test nested.imports[2] == Asset("bar.css")
6262
end
6363

6464
@testset "Async constructor" begin
6565
single = Async("foo.js")
66-
@test typeof(single) === Async
66+
@test typeof(single) === Async{Vector{Asset}}
6767
@test single.imports[1] == Asset("foo.js")
6868

6969
double = Async("foo" => "foo.js", Asset("bar.css"))
70-
@test typeof(double) === Async
70+
@test typeof(double) === Async{Vector{Asset}}
7171
@test double.imports[1] == Asset("foo" => "foo.js")
7272
@test double.imports[2] == Asset("bar.css")
7373

7474
nested = Async(Sync("stepone.js", "steptwo.js"), "bar.css")
75-
@test typeof(nested) === Async
75+
@test typeof(nested) === Async{Vector{Any}}
7676
@test nested.imports[1].imports[1] == Asset("stepone.js")
7777
@test nested.imports[1].imports[2] == Asset("steptwo.js")
7878
@test nested.imports[2] == Asset("bar.css")

0 commit comments

Comments
 (0)