From 3b4544311b7c513cd37122ee3fedf8bededf355a Mon Sep 17 00:00:00 2001 From: haljin Date: Wed, 27 May 2026 10:45:22 +0200 Subject: [PATCH] Fix the nested versioned fields bug --- config/config.exs | 2 +- lib/exgencode.ex | 15 +++++++++++---- lib/exgencode/encode_decode.ex | 20 ++++++++++++++------ mix.exs | 2 +- test/exgencode_test.exs | 16 ++++++++++++++++ test/helpers/test_pdu.ex | 4 ++++ 6 files changed, 47 insertions(+), 12 deletions(-) diff --git a/config/config.exs b/config/config.exs index 5b593a9..89ef556 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,6 +1,6 @@ # This file is responsible for configuring your application # and its dependencies with the aid of the Mix.Config module. -use Mix.Config +import Config # This configuration is loaded before any dependency and is restricted # to this project. If another project depends on this project, this diff --git a/lib/exgencode.ex b/lib/exgencode.ex index 24f6729..86900dd 100644 --- a/lib/exgencode.ex +++ b/lib/exgencode.ex @@ -416,7 +416,8 @@ defmodule Exgencode do field_name, props ), - props[:version] + props[:version], + props[:type] ) decode_fun = @@ -426,7 +427,8 @@ defmodule Exgencode do field_name, props ), - props[:version] + props[:version], + props[:type] ) {field_name, [{:encode, encode_fun}, {:decode, decode_fun} | props]} @@ -435,11 +437,16 @@ defmodule Exgencode do encode_fun = Exgencode.EncodeDecode.create_versioned_encode( Exgencode.EncodeDecode.wrap_custom_encode(field_name, props[:encode]), - props[:version] + props[:version], + props[:type] ) decode_fun = - Exgencode.EncodeDecode.create_versioned_decode(props[:decode], props[:version]) + Exgencode.EncodeDecode.create_versioned_decode( + props[:decode], + props[:version], + props[:type] + ) {field_name, props diff --git a/lib/exgencode/encode_decode.ex b/lib/exgencode/encode_decode.ex index 459cac4..6b898d7 100644 --- a/lib/exgencode/encode_decode.ex +++ b/lib/exgencode/encode_decode.ex @@ -3,11 +3,15 @@ defmodule Exgencode.EncodeDecode do Helper functions for generating encoding and decoding functions. """ - def create_versioned_encode(function, nil) do + def create_versioned_encode(function, nil, :subrecord) do + quote do: fn version -> unquote(function) end + end + + def create_versioned_encode(function, nil, _) do quote do: fn _ -> unquote(function) end end - def create_versioned_encode(function, version) do + def create_versioned_encode(function, version, _) do quote do fn nil -> @@ -23,11 +27,15 @@ defmodule Exgencode.EncodeDecode do end end - def create_versioned_decode(function, nil) do + def create_versioned_decode(function, nil, :subrecord) do + quote do: fn version -> unquote(function) end + end + + def create_versioned_decode(function, nil, _) do quote do: fn _ -> unquote(function) end end - def create_versioned_decode(function, version) do + def create_versioned_decode(function, version, _) do quote do fn nil -> @@ -46,7 +54,7 @@ defmodule Exgencode.EncodeDecode do def create_encode_fun(:subrecord, field_name, props) do basic_fun = quote do: fn %{unquote(field_name) => field_val} -> - <> + <> end wrap_conditional_encode(props, basic_fun) @@ -185,7 +193,7 @@ defmodule Exgencode.EncodeDecode do basic_fun = quote do fn pdu, binary -> - {field_value, rest_binary} = Exgencode.Pdu.decode(unquote(default), binary) + {field_value, rest_binary} = Exgencode.Pdu.decode(unquote(default), binary, version) {struct!(pdu, %{unquote(field_name) => field_value}), rest_binary} end end diff --git a/mix.exs b/mix.exs index 320b917..d6686ab 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Exgencode.Mixfile do def project do [ app: :exgencode, - version: "2.5.1", + version: "2.5.2", elixir: "~> 1.7", start_permanent: Mix.env() == :prod, deps: deps(), diff --git a/test/exgencode_test.exs b/test/exgencode_test.exs index a95044c..634764f 100644 --- a/test/exgencode_test.exs +++ b/test/exgencode_test.exs @@ -58,6 +58,14 @@ defmodule ExgencodeTest do assert <<10::size(16)>> == Exgencode.Pdu.encode(pdu, "1.0.0") assert <<10::size(16), 111::size(8)>> == Exgencode.Pdu.encode(pdu, "2.0.0") assert <<10::size(16), 111::size(8), 14::size(8)>> == Exgencode.Pdu.encode(pdu, "2.1.0") + + nested_pdu = %TestPdu.NestedVersionedMsg{nested: pdu} + + assert <<2::size(16), 10::size(16), 111::size(8), 14::size(8)>> == + Exgencode.Pdu.encode(nested_pdu) + + assert <<2::size(16), 10::size(16), 111::size(8)>> == + Exgencode.Pdu.encode(nested_pdu, "2.0.0") end test "versioning decode" do @@ -76,6 +84,14 @@ defmodule ExgencodeTest do assert {%TestPdu.VersionedMsg{}, <<111::size(8), 14::size(8)>>} = Exgencode.Pdu.decode(%TestPdu.VersionedMsg{}, binary, "1.0.0") + + nested_pdu = %TestPdu.NestedVersionedMsg{nested: %TestPdu.VersionedMsg{}} + binary = <<2::size(16), 10::size(16)>> + assert {^nested_pdu, <<>>} = Exgencode.Pdu.decode(%TestPdu.NestedVersionedMsg{}, binary, "1.0.0") + + nested_pdu = %TestPdu.NestedVersionedMsg{nested: %TestPdu.VersionedMsg{newerField: 111}} + binary = <<2::size(16), 10::size(16), 111::size(8)>> + assert {^nested_pdu, <<>>} = Exgencode.Pdu.decode(%TestPdu.NestedVersionedMsg{}, binary, "2.0.0") end test "versioned encode/decode symmetry" do diff --git a/test/helpers/test_pdu.ex b/test/helpers/test_pdu.ex index 3ec36a9..6463827 100644 --- a/test/helpers/test_pdu.ex +++ b/test/helpers/test_pdu.ex @@ -34,6 +34,10 @@ defmodule Exgencode.TestPdu do end ] + defpdu NestedVersionedMsg, + someField: [size: 16, default: 2], + nested: [type: :subrecord, default: %VersionedMsg{}] + defpdu EndianMsg, bigField: [default: 15, size: 32, endianness: :big], smallField: [default: 15, size: 32, endianness: :little]