Skip to content

Commit 25d1f55

Browse files
daniel-thomclaude
andcommitted
Identify components & supplemental attributes by integer ids
Port the integer-id identity model so components and supplemental attributes are identified by small integer ids assigned by SystemData when attached, instead of UUIDs, while keeping the Rust time-series backend. Mirrors the IS2.jl model. - InfrastructureSystemsInternal gains id::Int (UNASSIGNED_ID until attached); identity goes through get_id/set_id!. Time series keep their UUIDs. - SystemData tracks two independent id streams (next_component_id, next_supplemental_attribute_id, each from 1); component_uuids -> component_ids, subsystems -> Set{Int}; ComponentUUIDs -> ComponentIDs. ids are preserved across serialization (assign_id! advances the counter past restored ids). - Supplemental attribute associations use integer component_id/attribute_id. - Rust time-series glue threads (owner_id, owner_category) to the category-aware TimeSeriesStore.jl binding; assign_new_id! re-keys time series via replace_owner!. - Tests ported; forecast tests fixed to use strictly-increasing percentiles (the store validates this). Full InfrastructureSystems.jl test suite passes against the Rust backend. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 16157f0 commit 25d1f55

20 files changed

Lines changed: 707 additions & 460 deletions

src/InfrastructureSystems.jl

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,10 @@ Required interface functions for subtypes:
9393
9494
Optional interface functions:
9595
96-
- get_uuid()
96+
- [`get_id`](@ref)
97+
- [`supports_time_series`](@ref)
9798
98-
Subtypes may contain time series. Which requires
99-
100-
- `supports_time_series(::SupplementalAttribute)`
101-
102-
All subtypes must include an instance of ComponentUUIDs in order to track
99+
All subtypes must include an instance of [`ComponentIDs`](@ref) in order to track
103100
components attached to each attribute.
104101
"""
105102
abstract type SupplementalAttribute <: InfrastructureSystemsType end
@@ -155,7 +152,7 @@ include("static_time_series.jl")
155152
include("time_series_parameters.jl")
156153
include("containers.jl")
157154
include("component_container.jl")
158-
include("component_uuids.jl")
155+
include("component_ids.jl")
159156
include("geographic_supplemental_attribute.jl")
160157
include("generated/includes.jl")
161158
include("time_series_parser.jl")

src/component.jl

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
"""
2-
Assign a new UUID to the component.
2+
Assign a new integer id to the component, drawn from the system counter, and update any
3+
references to its old id in the time series store and supplemental attribute associations.
34
"""
4-
function assign_new_uuid_internal!(component::InfrastructureSystemsComponent)
5-
old_uuid = get_uuid(component)
6-
new_uuid = make_uuid()
5+
function assign_new_id_internal!(data, component::InfrastructureSystemsComponent)
6+
old_id = get_id(component)
7+
new_id = get_next_component_id!(data)
78
mgr = get_time_series_manager(component)
89
if !isnothing(mgr)
9-
_rust_replace_component_uuid!(mgr.data_store, old_uuid, new_uuid)
10+
_rust_replace_component_id!(mgr.data_store, old_id, new_id)
1011
end
1112

1213
associations = _get_supplemental_attribute_associations(component)
1314
if !isnothing(associations)
14-
replace_component_uuid!(associations, old_uuid, new_uuid)
15+
replace_component_id!(associations, old_id, new_id)
1516
end
1617

17-
set_uuid!(get_internal(component), new_uuid)
18+
set_id!(get_internal(component), new_id)
1819
return
1920
end
2021

@@ -47,8 +48,8 @@ end
4748
function clear_supplemental_attributes!(component::InfrastructureSystemsComponent)
4849
mgr = _get_supplemental_attributes_manager(component)
4950
isnothing(mgr) && return
50-
for uuid in list_associated_supplemental_attribute_uuids(mgr.associations, component)
51-
attribute = get_supplemental_attribute(mgr, uuid)
51+
for id in list_associated_supplemental_attribute_ids(mgr.associations, component)
52+
attribute = get_supplemental_attribute(mgr, id)
5253
remove_supplemental_attribute!(mgr, component, attribute)
5354
end
5455
@debug "Cleared attributes in $(summary(component))."
@@ -85,7 +86,7 @@ function _get_supplemental_attributes(
8586
isnothing(mgr) && return supplemental_attribute_type[]
8687
return supplemental_attribute_type[
8788
get_supplemental_attribute(mgr, x) for
88-
x in list_associated_supplemental_attribute_uuids(
89+
x in list_associated_supplemental_attribute_ids(
8990
mgr.associations,
9091
component,
9192
supplemental_attribute_type,
@@ -116,12 +117,12 @@ function _get_supplemental_attributes(
116117
mgr = _get_supplemental_attributes_manager(component)
117118
isnothing(mgr) && return [supplemental_attribute_type]
118119
attrs = Vector{supplemental_attribute_type}()
119-
for uuid in list_associated_supplemental_attribute_uuids(
120+
for id in list_associated_supplemental_attribute_ids(
120121
mgr.associations,
121122
component,
122123
supplemental_attribute_type,
123124
)
124-
attribute = get_supplemental_attribute(mgr, uuid)
125+
attribute = get_supplemental_attribute(mgr, id)
125126
if filter_func(attribute)
126127
push!(attrs, attribute)
127128
end
@@ -132,12 +133,12 @@ end
132133

133134
function get_supplemental_attribute(
134135
component::InfrastructureSystemsComponent,
135-
uuid::Base.UUID,
136+
id::Int,
136137
)
137138
mgr = _get_supplemental_attributes_manager(component)
138139
isnothing(mgr) &&
139140
error("$(summary(component)) does not have supplemental attributes")
140-
return get_supplemental_attribute(mgr, uuid)
141+
return get_supplemental_attribute(mgr, id)
141142
end
142143

143144
function _get_supplemental_attributes_manager(component::InfrastructureSystemsComponent)

src/component_ids.jl

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# This is an abstraction of a Set in order to enable de-serialization of supplemental
2+
# attributes.
3+
4+
"""
5+
Set-like storage of component integer ids attached to a [`SupplementalAttribute`](@ref).
6+
7+
Supplemental attribute subtypes include a `ComponentIDs` field so associations can be
8+
tracked and serialized without storing full component references.
9+
"""
10+
struct ComponentIDs <: InfrastructureSystemsType
11+
ids::Set{Int}
12+
13+
function ComponentIDs(ids = Set{Int}())
14+
new(ids)
15+
end
16+
end
17+
18+
Base.copy(x::ComponentIDs) = copy(x.ids)
19+
Base.delete!(x::ComponentIDs, id) = delete!(x.ids, id)
20+
Base.empty!(x::ComponentIDs) = empty!(x.ids)
21+
Base.filter!(f, x::ComponentIDs) = filter!(f, x.ids)
22+
Base.in(x, y::ComponentIDs) = in(x, y.ids)
23+
Base.isempty(x::ComponentIDs) = isempty(x.ids)
24+
Base.iterate(x::ComponentIDs, args...) = iterate(x.ids, args...)
25+
Base.length(x::ComponentIDs) = length(x.ids)
26+
Base.pop!(x::ComponentIDs) = pop!(x.ids)
27+
Base.pop!(x::ComponentIDs, y) = pop!(x.ids, y)
28+
Base.pop!(x::ComponentIDs, y, default) = pop!(x.ids, y, default)
29+
Base.push!(x::ComponentIDs, y) = push!(x.ids, y)
30+
Base.setdiff!(x::ComponentIDs, y::ComponentIDs) = setdiff!(x.ids, y.ids)
31+
Base.sizehint!(x::ComponentIDs, newsz) = sizehint!(x.ids, newsz)
32+
33+
function deserialize(::Type{ComponentIDs}, data::Dict)
34+
ids = Set{Int}()
35+
for id in data["ids"]
36+
push!(ids, Int(id))
37+
end
38+
return ComponentIDs(ids)
39+
end

src/component_uuids.jl

Lines changed: 0 additions & 33 deletions
This file was deleted.

src/components.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -316,18 +316,18 @@ See also: [`iterate_components`](@ref)
316316
function get_components(
317317
::Type{T},
318318
components::Components;
319-
component_uuids::Union{Nothing, Set{Base.UUID}} = nothing,
319+
component_ids::Union{Nothing, Set{Int}} = nothing,
320320
) where {T <: InfrastructureSystemsComponent}
321-
return iterate_instances(T, components.data, component_uuids)
321+
return iterate_instances(T, components.data, component_ids)
322322
end
323323

324324
function get_components(
325325
filter_func::Function,
326326
::Type{T},
327327
components::Components;
328-
component_uuids::Union{Nothing, Set{Base.UUID}} = nothing,
328+
component_ids::Union{Nothing, Set{Int}} = nothing,
329329
) where {T <: InfrastructureSystemsComponent}
330-
return iterate_instances(filter_func, T, components.data, component_uuids)
330+
return iterate_instances(filter_func, T, components.data, component_ids)
331331
end
332332

333333
"""

src/internal.jl

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,31 +28,46 @@ deserialize(T::Type{<:SystemUnitsSettings}, val::Dict) = deserialize_struct(T, v
2828
end
2929

3030
"""
31-
Internal storage common to InfrastructureSystems types.
31+
Sentinel value for the integer `id` of a component or supplemental attribute that has not
32+
yet been attached to a [`SystemData`](@ref). Assigned IDs start at 1.
33+
"""
34+
const UNASSIGNED_ID = 0
35+
36+
"""
37+
Internal storage common to [`InfrastructureSystemsType`](@ref)s.
38+
39+
Components and supplemental attributes are identified by an integer `id` assigned by the
40+
owning [`SystemData`](@ref) when they are attached (see [`get_id`](@ref)); it is
41+
[`UNASSIGNED_ID`](@ref) until then. The `uuid` is retained for time series, whose content
42+
and metadata are still identified by UUID. Each instance also holds optional
43+
[`SharedSystemReferences`](@ref) when attached to a system, optional unit metadata, and an
44+
optional user extension dictionary accessed through [`get_ext`](@ref).
3245
"""
3346
mutable struct InfrastructureSystemsInternal <: InfrastructureSystemsType
47+
id::Int
3448
uuid::Base.UUID
3549
shared_system_references::Union{Nothing, SharedSystemReferences}
3650
units_info::Union{Nothing, SystemUnitsSettings}
3751
ext::Union{Nothing, Dict{String, Any}}
3852
end
3953

4054
"""
41-
Creates InfrastructureSystemsInternal with a new UUID.
55+
Creates InfrastructureSystemsInternal with a new UUID and an unassigned integer id.
4256
"""
4357
InfrastructureSystemsInternal(;
58+
id = UNASSIGNED_ID,
4459
uuid = make_uuid(),
4560
shared_system_references = nothing,
4661
units_info = nothing,
4762
ext = nothing,
4863
) =
49-
InfrastructureSystemsInternal(uuid, shared_system_references, units_info, ext)
64+
InfrastructureSystemsInternal(id, uuid, shared_system_references, units_info, ext)
5065

5166
"""
5267
Creates InfrastructureSystemsInternal with an existing UUID.
5368
"""
5469
InfrastructureSystemsInternal(u::Base.UUID) =
55-
InfrastructureSystemsInternal(u, nothing, nothing, nothing)
70+
InfrastructureSystemsInternal(UNASSIGNED_ID, u, nothing, nothing, nothing)
5671

5772
"""
5873
Return a user-modifiable dictionary to store extra information.
@@ -76,6 +91,9 @@ end
7691
get_uuid(internal::InfrastructureSystemsInternal) = internal.uuid
7792
set_uuid!(internal::InfrastructureSystemsInternal, uuid) = internal.uuid = uuid
7893

94+
get_id(internal::InfrastructureSystemsInternal) = internal.id
95+
set_id!(internal::InfrastructureSystemsInternal, id::Int) = internal.id = id
96+
7997
function set_shared_system_references!(
8098
internal::InfrastructureSystemsInternal,
8199
refs::Union{Nothing, SharedSystemReferences},
@@ -94,6 +112,22 @@ function get_uuid(obj::InfrastructureSystemsType)
94112
return get_internal(obj).uuid
95113
end
96114

115+
"""
116+
Gets the integer id of a component or supplemental attribute. Returns [`UNASSIGNED_ID`](@ref)
117+
if the object has not been attached to a [`SystemData`](@ref).
118+
"""
119+
function get_id(obj::InfrastructureSystemsType)
120+
return get_internal(obj).id
121+
end
122+
123+
"""
124+
Sets the integer id of a component or supplemental attribute.
125+
"""
126+
function set_id!(obj::InfrastructureSystemsType, id::Int)
127+
set_id!(get_internal(obj), id)
128+
return
129+
end
130+
97131
"""
98132
Assign a new UUID.
99133
"""
@@ -139,7 +173,7 @@ function compare_values(
139173
)
140174
match = true
141175
for name in fieldnames(InfrastructureSystemsInternal)
142-
if name in exclude || (name == :uuid && !compare_uuids) ||
176+
if name in exclude || (name in (:uuid, :id) && !compare_uuids) ||
143177
name == :shared_system_references
144178
continue
145179
end

src/iterators.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@ function iterate_instances(
44
filter_func::Function,
55
::Type{T},
66
data::_ContainerTypes,
7-
uuids::Set{Base.UUID},
7+
ids::Set{Int},
88
) where {T <: InfrastructureSystemsType}
9-
func_uuids = x -> get_uuid(x) in uuids
10-
_filter_func = x -> filter_func(x) && func_uuids(x)
9+
func_ids = x -> get_id(x) in ids
10+
_filter_func = x -> filter_func(x) && func_ids(x)
1111
return iterate_instances(_filter_func, T, data, nothing)
1212
end
1313

1414
function iterate_instances(
1515
::Type{T},
1616
data::_ContainerTypes,
17-
uuids::Set{Base.UUID},
17+
ids::Set{Int},
1818
) where {T <: InfrastructureSystemsType}
19-
filter_func = x -> get_uuid(x) in uuids
19+
filter_func = x -> get_id(x) in ids
2020
return iterate_instances(filter_func, T, data, nothing)
2121
end
2222

0 commit comments

Comments
 (0)