From fc1362c743a3e5a5fccb1aaaea9d924386dd9397 Mon Sep 17 00:00:00 2001 From: stanislav Date: Wed, 12 Feb 2025 20:03:05 +0500 Subject: [PATCH] Add dynamic deserialization of AbstractTypes --- Project.toml | 1 + src/De/De.jl | 38 +++++++++++++------------------------- src/De/Deser.jl | 16 +++++++++++++++- src/Serde.jl | 2 ++ 4 files changed, 31 insertions(+), 26 deletions(-) diff --git a/Project.toml b/Project.toml index 188d31ae..bdf9f376 100644 --- a/Project.toml +++ b/Project.toml @@ -6,6 +6,7 @@ version = "3.5.0" CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" EzXML = "8f5d6c58-4d21-5cfd-889c-e3ad7ee6a615" +InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" diff --git a/src/De/De.jl b/src/De/De.jl index a310cf56..a41a6603 100644 --- a/src/De/De.jl +++ b/src/De/De.jl @@ -13,12 +13,20 @@ 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::MissingKeyError) + return print(io, "KeyError: required key '$(e.key)' is missing or invalid.") end -function Base.show(io::IO, e::TagError) - return print(io, "TagError: tag for method '$(e.tag)' is not declared") +struct UndefKeyError <: DeserError + type::Type +end + +function Base.show(io::IO, e::UndefKeyError) + print(io, "UndefKeyError: define `subtype_key(::Type{$(e.type)})` to specify the subtype field.") end struct WrongType <: DeserError @@ -38,26 +46,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 @@ -84,7 +72,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 diff --git a/src/De/Deser.jl b/src/De/Deser.jl index ee6f198e..260c3f11 100644 --- a/src/De/Deser.jl +++ b/src/De/Deser.jl @@ -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 @@ -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 @@ -411,6 +412,19 @@ end end end +subtype_key(::Type{T}) where {T<:Any} = nothing + +function deser(::AbstractType, ::Type{T}, data::AbstractDict{K,D})::T where {T,K,D} + field = subtype_key(T) + field === nothing && throw(UndefKeyError(T)) + for sub in subtypes(T) + if nameof(sub) == Symbol(data[K(field)]) + return deser(CustomType(), sub, data) + end + end + throw(MissingKeyError(field)) +end + function deser(::CustomType, ::Type{T}, data::AbstractVector{A})::T where {T<:Any,A<:Any} veclen = fieldcount(T) target = Vector{Any}(undef, veclen) diff --git a/src/Serde.jl b/src/Serde.jl index f8ac0b52..532a8965 100644 --- a/src/Serde.jl +++ b/src/Serde.jl @@ -1,5 +1,7 @@ module Serde +using InteractiveUtils + function deser end function parse_value end