@@ -3,15 +3,32 @@ unrolled_foreach!(f, ::Tuple{}) = nothing
33
44"""
55```julia
6- recursivecopy(a::Union{AbstractArray{T, N}, AbstractVectorOfArray{T, N}} )
6+ recursivecopy(a)
77```
88
99A recursive `copy` function. Acts like a `deepcopy` on arrays of arrays, but
10- like `copy` on arrays of scalars.
11- """
12- function recursivecopy (a)
13- deepcopy (a)
10+ like `copy` on arrays of scalars. For struct types, recursively copies each
11+ field, creating new instances while preserving the struct type.
12+
13+ ## Examples
14+
15+ ```julia
16+ # Basic array copying
17+ arr = [[1, 2], [3, 4]]
18+ copied = recursivecopy(arr) # New arrays at each level
19+
20+ # Struct copying
21+ struct MyStruct
22+ data::Vector{Float64}
23+ metadata::String
1424end
25+ original = MyStruct([1.0, 2.0], "test")
26+ copied = recursivecopy(original) # New struct with new vector
27+ ```
28+
29+ This is particularly useful for SciML ecosystem objects like `NonlinearSolution`
30+ where you need to copy the entire solution structure including all internal arrays.
31+ """
1532function recursivecopy (a:: Union {StaticArraysCore. SVector, StaticArraysCore. SMatrix,
1633 StaticArraysCore. SArray, Number})
1734 copy (a)
@@ -35,6 +52,42 @@ function recursivecopy(a::AbstractVectorOfArray)
3552 return b
3653end
3754
55+ function _is_basic_julia_type (T)
56+ # Check if this is a built-in Julia type that we should not handle as a user struct
57+ # We check the module to identify Core/Base types vs user-defined types
58+ mod = Base. parentmodule (T)
59+ return T <: AbstractString || T <: Number || T <: Symbol || T <: Tuple ||
60+ T <: UnitRange || T <: StepRange || T <: Regex ||
61+ T === Nothing || T === Missing ||
62+ mod === Core || mod === Base
63+ end
64+
65+ function recursivecopy (s:: T ) where {T}
66+ # Only handle user-defined immutable structs. Many basic Julia types (String, Symbol,
67+ # Tuple, etc.) are technically structs but should use copy() or return as-is.
68+ if Base. isstructtype (T) && ! _is_basic_julia_type (T)
69+ if Base. ismutabletype (T)
70+ error (" recursivecopy for mutable structs is not currently implemented. Use deepcopy instead." )
71+ else
72+ # Handle immutable structs only
73+ field_values = ntuple (fieldcount (T)) do i
74+ field_value = getfield (s, i)
75+ recursivecopy (field_value)
76+ end
77+ return T (field_values... )
78+ end
79+ elseif _is_basic_julia_type (T)
80+ # For basic Julia types, use copy if available, otherwise return as-is (for immutable types)
81+ if hasmethod (copy, Tuple{T})
82+ return copy (s)
83+ else
84+ return s # Immutable basic types like Symbol, Nothing, Missing don't need copying
85+ end
86+ else
87+ deepcopy (s)
88+ end
89+ end
90+
3891"""
3992```julia
4093recursivecopy!(b::AbstractArray{T, N}, a::AbstractArray{T, N})
0 commit comments