@@ -170,6 +170,79 @@ local function layoutstruct(fields, byteidx, bitoff)
170170 return spec , byteidx , bitoff
171171end
172172
173+ local function layoutunion (fields , byteidx , bitoff )
174+ assert (type (fields ) == " table" and # fields > 0 , " invalid type" )
175+ local spec = {
176+ pos = byteidx ,
177+ bitoff = bitoff ,
178+ bits = 0 ,
179+ bytes = 0 ,
180+ }
181+
182+ local specs = {}
183+ local maxsizefield = 0
184+ local byteidxmax = 0
185+ local bitoffmax = 0
186+ for _ , field in ipairs (fields ) do
187+ local key = field .key
188+ local type = field .type
189+ if type == nil then type = " number" end
190+ local build = assert (layout [type ], " unsupported type" )
191+ local field , byteidxtemp , bitofftemp = build (field , byteidx , bitoff )
192+
193+ if field .bits == nil then
194+ if field .bytes * 8 > maxsizefield then
195+ maxsizefield = field .bytes * 8
196+ byteidxmax = byteidxtemp
197+ bitoffmax = bitofftemp
198+ spec .bytes = byteidxtemp - spec .pos
199+ spec .bits = 8 * (spec .bytes )+ bitofftemp - spec .bitoff
200+ end
201+ else
202+ if field .bits > maxsizefield then
203+ maxsizefield = field .bits
204+ byteidxmax = byteidxtemp
205+ bitoffmax = bitofftemp
206+ spec .bytes = byteidxtemp - spec .pos
207+ spec .bits = 8 * (spec .bytes )+ bitofftemp - spec .bitoff
208+ end
209+ end
210+
211+ if key ~= nil then
212+ specs [key ] = field
213+ end
214+ end
215+ spec .fields = specs
216+ return spec , byteidxmax , bitoffmax
217+ end
218+
219+ function layout .union (field , ...)
220+ local spec , byteidx , bitoff = layoutunion (field , ... )
221+ function spec .read (self )
222+ local pointer = self [spec ]
223+ if pointer == nil then
224+ pointer = setmetatable ({ struct = spec , parent = self }, Pointer )
225+ self [spec ] = pointer
226+ end
227+ return pointer
228+ end
229+ function spec .write (self , value , key )
230+ if getmetatable (value ) == Pointer then
231+ local src , dst = value .struct , spec
232+ assert (src .bitoff == 0 and src .bits % 8 == 0
233+ and dst .bitoff == 0 and dst .bits % 8 == 0 , " unsupported" )
234+ assert (dst .bytes == src .bytes , " size mismatch" )
235+ local selfpos = rawget (self .parent , " pos" )
236+ local valuepos = rawget (value .parent , " pos" )
237+ memcopy (self .parent .buffer , value .parent .buffer ,
238+ selfpos + dst .pos , selfpos + dst .pos + dst .bytes - 1 , valuepos + src .pos )
239+ else
240+ error (" unsupported" )
241+ end
242+ end
243+ return spec , byteidx , bitoff
244+ end
245+
173246function layout .struct (field , ...)
174247 local spec , byteidx , bitoff = layoutstruct (field , ... )
175248 function spec .read (self )
0 commit comments