Skip to content

Commit 5e28dba

Browse files
author
CI
committed
Sync to GitHub
1 parent f86691d commit 5e28dba

2 files changed

Lines changed: 31 additions & 10 deletions

File tree

lib/bacnet/protocol/object_types/device.ex

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -252,19 +252,36 @@ defmodule BACnet.Protocol.ObjectTypes.Device do
252252
@external_resource BACstack.MixProject.get_vendor_ids_csv_file()
253253
@vendor_ids BACstack.MixProject.get_vendor_ids()
254254

255+
# Dialyzer is so hecking stupid - go love yourself with your stupid opaqueness contracts
256+
@dialyzer {:nowarn_function, get_vendor_ids: 0, get_vendor_ids_arr: 0, map_vendor_to_name: 1}
257+
258+
@spec get_vendor_ids_arr() :: :array.array(String.t())
259+
defp get_vendor_ids_arr(), do: @vendor_ids
260+
255261
@doc """
256262
Get the list of known vendor IDs to vendor names.
263+
264+
> #### Implementation Detail {: .info}
265+
> Internally the vendor IDs mapping is represented as an erlang array
266+
> and will be converted to a map. If you use this map multiple times in a row,
267+
> consider storing it in a variable as the conversion can be computational heavy.
257268
"""
258269
@spec get_vendor_ids() :: %{optional(non_neg_integer()) => String.t()}
259270
def get_vendor_ids() do
260-
@vendor_ids
271+
get_vendor_ids_arr()
272+
|> :array.sparse_to_orddict()
273+
|> Map.new()
261274
end
262275

263-
@spec map_vendor_to_name(non_neg_integer) :: String.t()
264-
defp map_vendor_to_name(id) do
265-
Map.get(@vendor_ids, id, "")
276+
@spec map_vendor_to_name(non_neg_integer()) :: String.t()
277+
defp map_vendor_to_name(id)
278+
279+
defp map_vendor_to_name(id) when is_integer(id) and id >= 0 do
280+
:array.get(id, get_vendor_ids_arr())
266281
end
267282

283+
defp map_vendor_to_name(_id), do: ""
284+
268285
@spec inhibit_object_check(t()) :: {:ok, t()}
269286
defp inhibit_object_check(obj) do
270287
# Only patch vendor name if empty

mix.exs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ defmodule BACstack.MixProject do
1818
deps: deps(),
1919
package: package(),
2020
dialyzer: [
21+
# Flags could be ["-Wno_opaque"]
22+
flags: [],
2123
ignore_warnings: "dialyzer.ignore-warnings.exs",
2224
plt_add_apps: [:mix]
2325
],
@@ -538,7 +540,8 @@ defmodule BACstack.MixProject do
538540
Path.join([__DIR__, "priv", "vendor_ids.csv"])
539541
end
540542

541-
@spec get_vendor_ids() :: %{optional(non_neg_integer()) => String.t()}
543+
# Returns an :array.array(String.t()), but dialyzer doesn't like that
544+
@spec get_vendor_ids() :: term()
542545
def get_vendor_ids() do
543546
if not File.exists?(get_vendor_ids_csv_file()) do
544547
Mix.Task.run("bacnet.dl.vendorids")
@@ -547,18 +550,19 @@ defmodule BACstack.MixProject do
547550
parse_vendor_ids_csv()
548551
end
549552

550-
@spec parse_vendor_ids_csv() :: %{optional(non_neg_integer()) => String.t()}
553+
# Returns an :array.array(String.t()), but dialyzer doesn't like that
554+
@spec parse_vendor_ids_csv() :: term()
551555
def parse_vendor_ids_csv() do
552556
get_vendor_ids_csv_file()
553-
|> File.read!()
554-
|> String.split("\n")
557+
|> File.stream!()
555558
|> Stream.flat_map(fn line ->
556559
case String.split(line, ";") do
557-
[id, name] -> [{String.to_integer(id), name}]
560+
[id, name] -> [{String.to_integer(id), String.trim(name)}]
558561
_else -> []
559562
end
560563
end)
561-
|> Map.new()
564+
|> Enum.sort_by(&elem(&1, 0))
565+
|> :array.from_orddict("")
562566
end
563567

564568
#### Download BACnet Vendor IDs list from the BACnet website END ####

0 commit comments

Comments
 (0)