detached 7b60891

make encoding return an error instead of panic (#82)

* make encoding return an error instead of panic

This also adds support for unsafe.Pointer types.

* remove success variables and remove excess var
commit
7b60891325c492c051350418d742c735ec484fe9
author
TotallyGamerJet · · 2022-12-16 18:54 UTC
committer
GitHub · · 2022-12-16 18:54 UTC
parent
39261b6
signature
GPG Unverified4AEE18F83AFDEB23 The key is unknown
1 file · +62 -39
M objc/objc_runtime_darwin.go +62 -39
@@ -245,8 +245,7 @@ func RegisterClass(object Selector) (Class, error) {
245245 if len(split) > 2 {
246246 // Add Protocols
247247 for _, n := range split[2:] {
248- succeed := class.AddProtocol(GetProtocol(n))
249- if !succeed {
248+ if !class.AddProtocol(GetProtocol(n)) {
250249 return 0, fmt.Errorf("objc: couldn't add Protocol %s", n)
251250 }
252251 }
@@ -275,8 +274,11 @@ func RegisterClass(object Selector) (Class, error) {
275274 if err != nil {
276275 return 0, fmt.Errorf("objc: couldn't add Method %s: %w", met.Name, err)
277276 }
278- succeed := class.AddMethod(sel, imp, encodeFunc(fn))
279- if !succeed {
277+ encoding, err := encodeFunc(fn)
278+ if err != nil {
279+ return 0, fmt.Errorf("objc: couldn't add Method %s: %w", met.Name, err)
280+ }
281+ if !class.AddMethod(sel, imp, encoding) {
280282 return 0, fmt.Errorf("objc: couldn't add Method %s", met.Name)
281283 }
282284 }
@@ -286,8 +288,11 @@ func RegisterClass(object Selector) (Class, error) {
286288 f := strct.Field(i)
287289 size := f.Type.Size()
288290 alignment := uint8(math.Log2(float64(f.Type.Align())))
289- succeed := class_addIvar(class, f.Name, size, alignment, encodeType(f.Type))
290- if !succeed {
291+ enc, err := encodeType(f.Type, false)
292+ if err != nil {
293+ return 0, fmt.Errorf("objc: couldn't add Ivar %s: %w", f.Name, err)
294+ }
295+ if !class_addIvar(class, f.Name, size, alignment, enc) {
291296 return 0, fmt.Errorf("objc: couldn't add Ivar %s", f.Name)
292297 }
293298 if offset := class.InstanceVariable(f.Name).Offset(); offset != f.Offset {
@@ -321,74 +326,85 @@ const (
321326 encCharPtr = "*"
322327 encStructBegin = "{"
323328 encStructEnd = "}"
329+ encUnsafePtr = "^v"
324330 )
325331
326332 // encodeType returns a string representing a type as if it was given to @encode(typ)
327333 // Source: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100
328-func encodeType(typ reflect.Type) string {
334+func encodeType(typ reflect.Type, insidePtr bool) (string, error) {
329335 switch typ {
330336 case reflect.TypeOf(Class(0)):
331- return encClass
337+ return encClass, nil
332338 case reflect.TypeOf(ID(0)):
333- return encId
339+ return encId, nil
334340 case reflect.TypeOf(SEL(0)):
335- return encSelector
341+ return encSelector, nil
336342 }
337343
338344 kind := typ.Kind()
339345 switch kind {
340346 case reflect.Bool:
341- return encBool
347+ return encBool, nil
342348 case reflect.Int:
343- return encLong
349+ return encLong, nil
344350 case reflect.Int8:
345- return encChar
351+ return encChar, nil
346352 case reflect.Int16:
347- return encShort
353+ return encShort, nil
348354 case reflect.Int32:
349- return encInt
355+ return encInt, nil
350356 case reflect.Int64:
351- return encULong
357+ return encULong, nil
352358 case reflect.Uint:
353- return encULong
359+ return encULong, nil
354360 case reflect.Uint8:
355- return encUChar
361+ return encUChar, nil
356362 case reflect.Uint16:
357- return encUShort
363+ return encUShort, nil
358364 case reflect.Uint32:
359- return encUInt
365+ return encUInt, nil
360366 case reflect.Uint64:
361- return encULong
367+ return encULong, nil
362368 case reflect.Uintptr:
363- return encPtr
369+ return encPtr, nil
364370 case reflect.Float32:
365- return encFloat
371+ return encFloat, nil
366372 case reflect.Float64:
367- return encDouble
373+ return encDouble, nil
368374 case reflect.Ptr:
369- return encPtr + encodeType(typ.Elem())
375+ enc, err := encodeType(typ.Elem(), true)
376+ return encPtr + enc, err
370377 case reflect.Struct:
378+ if insidePtr {
379+ return encStructBegin + typ.Name() + encStructEnd, nil
380+ }
371381 var encoding = encStructBegin
372382 encoding += typ.Name()
373383 encoding += "="
374384 for i := 0; i < typ.NumField(); i++ {
375385 f := typ.Field(i)
376- encoding += encodeType(f.Type)
386+ tmp, err := encodeType(f.Type, false)
387+ if err != nil {
388+ return "", err
389+ }
390+ encoding += tmp
377391 }
378392 encoding = encStructEnd
379- return encoding
393+ return encoding, nil
394+ case reflect.UnsafePointer:
395+ return encUnsafePtr, nil
380396 case reflect.String:
381- return encCharPtr
397+ return encCharPtr, nil
382398 }
383399
384- panic(fmt.Sprintf("objc: unhandled/invalid kind %v typed %v", kind, typ))
400+ return "", errors.New(fmt.Sprintf("unhandled/invalid kind %v typed %v", kind, typ))
385401 }
386402
387403 // encodeFunc returns a functions type as if it was given to @encode(fn)
388-func encodeFunc(fn interface{}) string {
404+func encodeFunc(fn interface{}) (string, error) {
389405 typ := reflect.TypeOf(fn)
390406 if typ.Kind() != reflect.Func {
391- panic("objc: not a func")
407+ return "", errors.New("not a func")
392408 }
393409
394410 encoding := ""
@@ -396,22 +412,29 @@ func encodeFunc(fn interface{}) string {
396412 case 0:
397413 encoding += encVoid
398414 case 1:
399- encoding += encodeType(typ.Out(0))
415+ tmp, err := encodeType(typ.Out(0), false)
416+ if err != nil {
417+ return "", err
418+ }
419+ encoding += tmp
400420 default:
401- panic("objc: too many output parameters")
421+ return "", errors.New("too many output parameters")
402422 }
403423
404- if typ.NumIn() == 0 {
405- panic("objc: func doesn't take ID and SEL as its first two parameters")
424+ if typ.NumIn() < 2 {
425+ return "", errors.New("func doesn't take ID and SEL as its first two parameters")
406426 }
407427
408- encoding += encodeType(typ.In(0))
409- encoding += encSelector
428+ encoding += encId
410429
411430 for i := 1; i < typ.NumIn(); i++ {
412- encoding += encodeType(typ.In(i))
431+ tmp, err := encodeType(typ.In(i), false)
432+ if err != nil {
433+ return "", err
434+ }
435+ encoding += tmp
413436 }
414- return encoding
437+ return encoding, nil
415438 }
416439
417440 // SuperClass returns the superclass of a class.
@@ -245,8 +245,7 @@ func RegisterClass(object Selector) (Class, error) {
245 if len(split) > 2 {245 if len(split) > 2 {
246 // Add Protocols246 // Add Protocols
247 for _, n := range split[2:] {247 for _, n := range split[2:] {
248- succeed := class.AddProtocol(GetProtocol(n))248+ if !class.AddProtocol(GetProtocol(n)) {
249- if !succeed {
250 return 0, fmt.Errorf("objc: couldn't add Protocol %s", n)249 return 0, fmt.Errorf("objc: couldn't add Protocol %s", n)
251 }250 }
252 }251 }
@@ -275,8 +274,11 @@ func RegisterClass(object Selector) (Class, error) {
275 if err != nil {274 if err != nil {
276 return 0, fmt.Errorf("objc: couldn't add Method %s: %w", met.Name, err)275 return 0, fmt.Errorf("objc: couldn't add Method %s: %w", met.Name, err)
277 }276 }
278- succeed := class.AddMethod(sel, imp, encodeFunc(fn))277+ encoding, err := encodeFunc(fn)
279- if !succeed {278+ if err != nil {
279+ return 0, fmt.Errorf("objc: couldn't add Method %s: %w", met.Name, err)
280+ }
281+ if !class.AddMethod(sel, imp, encoding) {
280 return 0, fmt.Errorf("objc: couldn't add Method %s", met.Name)282 return 0, fmt.Errorf("objc: couldn't add Method %s", met.Name)
281 }283 }
282 }284 }
@@ -286,8 +288,11 @@ func RegisterClass(object Selector) (Class, error) {
286 f := strct.Field(i)288 f := strct.Field(i)
287 size := f.Type.Size()289 size := f.Type.Size()
288 alignment := uint8(math.Log2(float64(f.Type.Align())))290 alignment := uint8(math.Log2(float64(f.Type.Align())))
289- succeed := class_addIvar(class, f.Name, size, alignment, encodeType(f.Type))291+ enc, err := encodeType(f.Type, false)
290- if !succeed {292+ if err != nil {
293+ return 0, fmt.Errorf("objc: couldn't add Ivar %s: %w", f.Name, err)
294+ }
295+ if !class_addIvar(class, f.Name, size, alignment, enc) {
291 return 0, fmt.Errorf("objc: couldn't add Ivar %s", f.Name)296 return 0, fmt.Errorf("objc: couldn't add Ivar %s", f.Name)
292 }297 }
293 if offset := class.InstanceVariable(f.Name).Offset(); offset != f.Offset {298 if offset := class.InstanceVariable(f.Name).Offset(); offset != f.Offset {
@@ -321,74 +326,85 @@ const (
321 encCharPtr = "*"326 encCharPtr = "*"
322 encStructBegin = "{"327 encStructBegin = "{"
323 encStructEnd = "}"328 encStructEnd = "}"
329+ encUnsafePtr = "^v"
324 )330 )
325 331
326 // encodeType returns a string representing a type as if it was given to @encode(typ)332 // encodeType returns a string representing a type as if it was given to @encode(typ)
327 // Source: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100333 // Source: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100
328-func encodeType(typ reflect.Type) string {334+func encodeType(typ reflect.Type, insidePtr bool) (string, error) {
329 switch typ {335 switch typ {
330 case reflect.TypeOf(Class(0)):336 case reflect.TypeOf(Class(0)):
331- return encClass337+ return encClass, nil
332 case reflect.TypeOf(ID(0)):338 case reflect.TypeOf(ID(0)):
333- return encId339+ return encId, nil
334 case reflect.TypeOf(SEL(0)):340 case reflect.TypeOf(SEL(0)):
335- return encSelector341+ return encSelector, nil
336 }342 }
337 343
338 kind := typ.Kind()344 kind := typ.Kind()
339 switch kind {345 switch kind {
340 case reflect.Bool:346 case reflect.Bool:
341- return encBool347+ return encBool, nil
342 case reflect.Int:348 case reflect.Int:
343- return encLong349+ return encLong, nil
344 case reflect.Int8:350 case reflect.Int8:
345- return encChar351+ return encChar, nil
346 case reflect.Int16:352 case reflect.Int16:
347- return encShort353+ return encShort, nil
348 case reflect.Int32:354 case reflect.Int32:
349- return encInt355+ return encInt, nil
350 case reflect.Int64:356 case reflect.Int64:
351- return encULong357+ return encULong, nil
352 case reflect.Uint:358 case reflect.Uint:
353- return encULong359+ return encULong, nil
354 case reflect.Uint8:360 case reflect.Uint8:
355- return encUChar361+ return encUChar, nil
356 case reflect.Uint16:362 case reflect.Uint16:
357- return encUShort363+ return encUShort, nil
358 case reflect.Uint32:364 case reflect.Uint32:
359- return encUInt365+ return encUInt, nil
360 case reflect.Uint64:366 case reflect.Uint64:
361- return encULong367+ return encULong, nil
362 case reflect.Uintptr:368 case reflect.Uintptr:
363- return encPtr369+ return encPtr, nil
364 case reflect.Float32:370 case reflect.Float32:
365- return encFloat371+ return encFloat, nil
366 case reflect.Float64:372 case reflect.Float64:
367- return encDouble373+ return encDouble, nil
368 case reflect.Ptr:374 case reflect.Ptr:
369- return encPtr + encodeType(typ.Elem())375+ enc, err := encodeType(typ.Elem(), true)
376+ return encPtr + enc, err
370 case reflect.Struct:377 case reflect.Struct:
378+ if insidePtr {
379+ return encStructBegin + typ.Name() + encStructEnd, nil
380+ }
371 var encoding = encStructBegin381 var encoding = encStructBegin
372 encoding += typ.Name()382 encoding += typ.Name()
373 encoding += "="383 encoding += "="
374 for i := 0; i < typ.NumField(); i++ {384 for i := 0; i < typ.NumField(); i++ {
375 f := typ.Field(i)385 f := typ.Field(i)
376- encoding += encodeType(f.Type)386+ tmp, err := encodeType(f.Type, false)
387+ if err != nil {
388+ return "", err
389+ }
390+ encoding += tmp
377 }391 }
378 encoding = encStructEnd392 encoding = encStructEnd
379- return encoding393+ return encoding, nil
394+ case reflect.UnsafePointer:
395+ return encUnsafePtr, nil
380 case reflect.String:396 case reflect.String:
381- return encCharPtr397+ return encCharPtr, nil
382 }398 }
383 399
384- panic(fmt.Sprintf("objc: unhandled/invalid kind %v typed %v", kind, typ))400+ return "", errors.New(fmt.Sprintf("unhandled/invalid kind %v typed %v", kind, typ))
385 }401 }
386 402
387 // encodeFunc returns a functions type as if it was given to @encode(fn)403 // encodeFunc returns a functions type as if it was given to @encode(fn)
388-func encodeFunc(fn interface{}) string {404+func encodeFunc(fn interface{}) (string, error) {
389 typ := reflect.TypeOf(fn)405 typ := reflect.TypeOf(fn)
390 if typ.Kind() != reflect.Func {406 if typ.Kind() != reflect.Func {
391- panic("objc: not a func")407+ return "", errors.New("not a func")
392 }408 }
393 409
394 encoding := ""410 encoding := ""
@@ -396,22 +412,29 @@ func encodeFunc(fn interface{}) string {
396 case 0:412 case 0:
397 encoding += encVoid413 encoding += encVoid
398 case 1:414 case 1:
399- encoding += encodeType(typ.Out(0))415+ tmp, err := encodeType(typ.Out(0), false)
416+ if err != nil {
417+ return "", err
418+ }
419+ encoding += tmp
400 default:420 default:
401- panic("objc: too many output parameters")421+ return "", errors.New("too many output parameters")
402 }422 }
403 423
404- if typ.NumIn() == 0 {424+ if typ.NumIn() < 2 {
405- panic("objc: func doesn't take ID and SEL as its first two parameters")425+ return "", errors.New("func doesn't take ID and SEL as its first two parameters")
406 }426 }
407 427
408- encoding += encodeType(typ.In(0))428+ encoding += encId
409- encoding += encSelector
410 429
411 for i := 1; i < typ.NumIn(); i++ {430 for i := 1; i < typ.NumIn(); i++ {
412- encoding += encodeType(typ.In(i))431+ tmp, err := encodeType(typ.In(i), false)
432+ if err != nil {
433+ return "", err
434+ }
435+ encoding += tmp
413 }436 }
414- return encoding437+ return encoding, nil
415 }438 }
416 439
417 // SuperClass returns the superclass of a class.440 // SuperClass returns the superclass of a class.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 102

↑↓ moveenter openesc close