@@ -71,4 +71,105 @@ function init(allocator=default_aws_allocator())
7171 return
7272end
7373
74+ # utilities for interacting with AWS library APIs
75+
76+ # like a Ref, but for a field of a struct
77+ # many AWS APIs take a pointer to an aws struct, so this makes it convenient to to pass
78+ # a field of a wrapper struct to a library function
79+ struct FieldRef{T, S}
80+ x:: T
81+ field:: Symbol
82+
83+ function FieldRef (x:: T , field:: Symbol ) where {T}
84+ @assert isconcretetype (T) && ismutabletype (T) " only fields of mutable types are supported with FieldRef"
85+ S = fieldtype (T, field)
86+ @assert isconcretetype (S) && ! ismutabletype (S) " field type must be concrete and immutable for FieldRef"
87+ return new {T, S} (x, field)
88+ end
89+ end
90+
91+ function Base. unsafe_convert (P:: Union{Type{Ptr{S}},Type{Ptr{Cvoid}}} , x:: FieldRef{T, S} ) where {T, S}
92+ return P (pointer_from_objref (x. x) + fieldoffset (T, Base. fieldindex (T, x. field)))
93+ end
94+
95+ Base. pointer (x:: FieldRef{S, T} ) where {S, T} = Base. unsafe_convert (Ptr{T}, x)
96+
97+ # wraps a pointer to a struct and allows get/set on fields w/o unsafe_loading the entire struct
98+ struct StructRef{T}
99+ ptr:: Ptr{T}
100+
101+ function StructRef (ptr:: Ptr{T} ) where {T}
102+ @assert isconcretetype (T) " only concrete struct types are supported with StructRef"
103+ return new {T} (ptr)
104+ end
105+ end
106+
107+ function Base. getproperty (x:: StructRef{T} , k:: Symbol ) where {T}
108+ S = fieldtype (T, k)
109+ @assert isconcretetype (S) && ! ismutabletype (S) " field type must be concrete and immutable for StructRef"
110+ return unsafe_load (Ptr {S} (Ptr {UInt8} (getfield (x, :ptr )) + fieldoffset (T, Base. fieldindex (T, k))))
111+ end
112+
113+ function Base. setproperty! (x:: StructRef{T} , k:: Symbol , v) where {T}
114+ S = fieldtype (T, k)
115+ @assert isconcretetype (S) && ! ismutabletype (S) " field type must be concrete and immutable for StructRef"
116+ unsafe_store! (Ptr {S} (Ptr {UInt8} (getfield (x, :ptr )) + fieldoffset (T, Base. fieldindex (T, k))), convert (S, v))
117+ return v
118+ end
119+
120+ # simple threadsafe Future impl appropriate for use with the common callback patterns in AWS libs
121+ mutable struct Future{T}
122+ const notify:: Threads.Condition
123+ @atomic set:: Int8 # if 0, result is undefined, 1 means result is T, 2 means result is an exception
124+ result:: Union{Exception, T} # undefined initially
125+ Future {T} () where {T} = new {T} (Threads. Condition (), 0 )
126+ end
127+
128+ Base. pointer (f:: Future ) = pointer_from_objref (f)
129+ Future (ptr:: Ptr ) = unsafe_pointer_to_objref (ptr):: Future
130+ Future {T} (ptr:: Ptr ) where {T} = unsafe_pointer_to_objref (ptr):: Future{T}
131+
132+ function Base. wait (f:: Future{T} ) where {T}
133+ set = @atomic f. set
134+ set == 1 && return f. result:: T
135+ set == 2 && throw (f. result:: Exception )
136+ lock (f. notify) # acquire barrier
137+ try
138+ set = f. set
139+ set == 1 && return f. result:: T
140+ set == 2 && throw (f. result:: Exception )
141+ wait (f. notify)
142+ finally
143+ unlock (f. notify) # release barrier
144+ end
145+ if f. set == 1
146+ return f. result:: T
147+ else
148+ @assert isdefined (f, :result )
149+ throw (f. result:: Exception )
150+ end
151+ end
152+
153+ capture (e:: Exception ) = CapturedException (e, Base. backtrace ())
154+
155+ function Base. notify (f:: Future{T} , x:: Union{Exception, T} ) where {T}
156+ lock (f. notify) # acquire barrier
157+ try
158+ if f. set == Int8 (0 )
159+ if x isa Exception
160+ set = Int8 (2 )
161+ f. result = x
162+ else
163+ set = Int8 (1 )
164+ f. result = x
165+ end
166+ @atomic :release f. set = set
167+ notify (f. notify)
168+ end
169+ finally
170+ unlock (f. notify)
171+ end
172+ nothing
173+ end
174+
74175end
0 commit comments