Skip to content

Commit

Permalink
Add dynamic deserialization of AbstractTypes
Browse files Browse the repository at this point in the history
  • Loading branch information
gryumov committed Feb 12, 2025
1 parent a8b7019 commit 186d12d
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 26 deletions.
30 changes: 5 additions & 25 deletions src/De/De.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ function Base.show(io::IO, e::ParamError)
)
end

struct TagError <: DeserError
tag::Any
struct MissingKeyError <: DeserError
key::Any
end

function Base.show(io::IO, e::TagError)
return print(io, "TagError: tag for method '$(e.tag)' is not declared")
function Base.show(io::IO, e::MissingKeyError)
return print(io, "KeyError: required key '$(e.key)' is missing or invalid.")
end

struct WrongType <: DeserError
Expand All @@ -38,26 +38,6 @@ end

include("Deser.jl")

function tag(::Type{T}, ::Val{x}) where {T,x}
return throw(TagError(x))
end

tag(::Type{T}, ::Nothing) where {T} = T

(tag_key(::Type)::Nothing) = nothing
(tag_val(::Type{T}, ::Nothing, v)::Nothing) where {T} = nothing

function tag_val(::Type{T}, k, v) where {T}
try
Val(Symbol(v[k]))
catch
throw(ParamError(k))
end
end

deser_type(::Type{T}, x) where {T} = tag(T, tag_val(T, tag_key(T), x))
deser_value(::Type{T}, x) where {T} = x

"""
Serde.to_deser(::Type{T}, x) -> T
Expand All @@ -84,7 +64,7 @@ julia> Serde.to_deser(Person, person_data)
Person("Michael", 25, Info(12, 2500))
```
"""
to_deser(::Type{T}, x) where {T} = deser(deser_type(T, x), deser_value(T, x))
to_deser(::Type{T}, x) where {T} = deser(T, x)

to_deser(::Type{Nothing}, x) = nothing
to_deser(::Type{Missing}, x) = missing
Expand Down
22 changes: 21 additions & 1 deletion src/De/Deser.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ For more details:
"""
abstract type ClassType end

struct AbstractType <: ClassType end
struct CustomType <: ClassType end
struct NullType <: ClassType end
struct PrimitiveType <: ClassType end
Expand Down Expand Up @@ -214,7 +215,7 @@ See also [`Serde.nulltype`](@ref), [`Serde.default_value`](@ref), [`Serde.isempt
## Examples:
Let's make a custom type `Computer` with the following fields and constructor.
Let's make a custom type `Computer` with the following fields and constructor.
```julia
struct Computer
cpu::String
Expand Down Expand Up @@ -411,6 +412,25 @@ end
end
end

function subtype_key(::Type{T}) where {T<:Any}
error("Define `subtype_key(::Type{$T})::Union{String,Symbol}` to specify the subtype field.")
end

function subtypes(::Type{T}) where {T<:Any}
error("Define `get_subtypes(::Type{$T})::Vector{Type}` to specify the available subtypes.")
end

function deser(::AbstractType, ::Type{T}, data::AbstractDict{K,D})::T where {T,K,D}
key = subtype_key(T)::Union{String,Symbol}
key_val = Symbol(data[K(key)])
for sub in subtypes(T)
if nameof(sub) == key_val
return deser(CustomType(), sub, data)
end
end
throw(MissingKeyError(key))
end

function deser(::CustomType, ::Type{T}, data::AbstractVector{A})::T where {T<:Any,A<:Any}
veclen = fieldcount(T)
target = Vector{Any}(undef, veclen)
Expand Down

0 comments on commit 186d12d

Please sign in to comment.