GIR: Extract `ByteSlice` and `GoStringSlice` from `purego` and use them instead of our custom conversion function when generating `[]string` property getters and setters
Signed-off-by: Felicitas Pojtinger <felicitas@pojtinger.com>
- commit
- ee17818d1377cc2ed124f5fa55d640e566566e8a
- author
- Felicitas Pojtinger · · 2025-10-31 05:57 UTC
- committer
- Jeroen Wijenbergh · · 2025-12-01 16:10 UTC
- parent
- 86a6933
- signature
- unsigned
3 files · +55 -38
M internal/core/core.go +51 -0
| @@ -158,6 +158,57 @@ func GetPaths(name string) []string { | |||
| 158 | 158 | panic(fmt.Sprintf("Path for library: %s not found. Please set the path to this library shared object file manually with env variable: %s or PUREGOTK_LIB_FOLDER. Or make sure pkg-config is setup correctly", strings.ToLower(name), ev)) | |
| 159 | 159 | } | |
| 160 | 160 | ||
| 161 | + | // hasSuffix tests whether the string s ends with suffix. | |
| 162 | + | // This function was copied from purego | |
| 163 | + | func hasSuffix(s, suffix string) bool { | |
| 164 | + | return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix | |
| 165 | + | } | |
| 166 | + | ||
| 167 | + | // ByteSlice creates a pointer to a byte slice of C strings | |
| 168 | + | // This function was copied from purego | |
| 169 | + | func ByteSlice(name []string) **byte { | |
| 170 | + | if name == nil { | |
| 171 | + | return nil | |
| 172 | + | } | |
| 173 | + | res := make([]*byte, len(name)+1) | |
| 174 | + | for i, v := range name { | |
| 175 | + | res[i] = CString(v) | |
| 176 | + | } | |
| 177 | + | ||
| 178 | + | // the last element is NULL terminated for GTK | |
| 179 | + | res[len(name)] = nil | |
| 180 | + | return &res[0] | |
| 181 | + | } | |
| 182 | + | ||
| 183 | + | // CString converts a go string to *byte that can be passed to C code. | |
| 184 | + | // This function was copied from purego | |
| 185 | + | func CString(name string) *byte { | |
| 186 | + | if hasSuffix(name, "\x00") { | |
| 187 | + | return &(*(*[]byte)(unsafe.Pointer(&name)))[0] | |
| 188 | + | } | |
| 189 | + | b := make([]byte, len(name)+1) | |
| 190 | + | copy(b, name) | |
| 191 | + | return &b[0] | |
| 192 | + | } | |
| 193 | + | ||
| 194 | + | // GoStringSlice gets a string slice from a char** array | |
| 195 | + | // This function was copied from purego | |
| 196 | + | func GoStringSlice(c uintptr) []string { | |
| 197 | + | var ret []string | |
| 198 | + | for i := 0; ; i++ { | |
| 199 | + | ptrAddr := c + uintptr(i)*unsafe.Sizeof(uintptr(0)) | |
| 200 | + | addr := *(*unsafe.Pointer)(unsafe.Pointer(&ptrAddr)) | |
| 201 | + | // We take the address and then dereference it to trick go vet from creating a possible misuse of unsafe.Pointer | |
| 202 | + | ptr := *(*uintptr)(addr) | |
| 203 | + | if ptr == 0 { | |
| 204 | + | break | |
| 205 | + | } | |
| 206 | + | ret = append(ret, GoString(ptr)) | |
| 207 | + | } | |
| 208 | + | ||
| 209 | + | return ret | |
| 210 | + | } | |
| 211 | + | ||
| 161 | 212 | // GoString copies a char* to a Go string. | |
| 162 | 213 | // This function was copied from purego | |
| 163 | 214 | func GoString(c uintptr) string { | |
| @@ -158,6 +158,57 @@ func GetPaths(name string) []string { | |||||
| 158 | panic(fmt.Sprintf("Path for library: %s not found. Please set the path to this library shared object file manually with env variable: %s or PUREGOTK_LIB_FOLDER. Or make sure pkg-config is setup correctly", strings.ToLower(name), ev)) | 158 | panic(fmt.Sprintf("Path for library: %s not found. Please set the path to this library shared object file manually with env variable: %s or PUREGOTK_LIB_FOLDER. Or make sure pkg-config is setup correctly", strings.ToLower(name), ev)) | ||
| 159 | } | 159 | } | ||
| 160 | 160 | ||||
| 161 | + | // hasSuffix tests whether the string s ends with suffix. | |||
| 162 | + | // This function was copied from purego | |||
| 163 | + | func hasSuffix(s, suffix string) bool { | |||
| 164 | + | return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix | |||
| 165 | + | } | |||
| 166 | + | ||||
| 167 | + | // ByteSlice creates a pointer to a byte slice of C strings | |||
| 168 | + | // This function was copied from purego | |||
| 169 | + | func ByteSlice(name []string) **byte { | |||
| 170 | + | if name == nil { | |||
| 171 | + | return nil | |||
| 172 | + | } | |||
| 173 | + | res := make([]*byte, len(name)+1) | |||
| 174 | + | for i, v := range name { | |||
| 175 | + | res[i] = CString(v) | |||
| 176 | + | } | |||
| 177 | + | ||||
| 178 | + | // the last element is NULL terminated for GTK | |||
| 179 | + | res[len(name)] = nil | |||
| 180 | + | return &res[0] | |||
| 181 | + | } | |||
| 182 | + | ||||
| 183 | + | // CString converts a go string to *byte that can be passed to C code. | |||
| 184 | + | // This function was copied from purego | |||
| 185 | + | func CString(name string) *byte { | |||
| 186 | + | if hasSuffix(name, "\x00") { | |||
| 187 | + | return &(*(*[]byte)(unsafe.Pointer(&name)))[0] | |||
| 188 | + | } | |||
| 189 | + | b := make([]byte, len(name)+1) | |||
| 190 | + | copy(b, name) | |||
| 191 | + | return &b[0] | |||
| 192 | + | } | |||
| 193 | + | ||||
| 194 | + | // GoStringSlice gets a string slice from a char** array | |||
| 195 | + | // This function was copied from purego | |||
| 196 | + | func GoStringSlice(c uintptr) []string { | |||
| 197 | + | var ret []string | |||
| 198 | + | for i := 0; ; i++ { | |||
| 199 | + | ptrAddr := c + uintptr(i)*unsafe.Sizeof(uintptr(0)) | |||
| 200 | + | addr := *(*unsafe.Pointer)(unsafe.Pointer(&ptrAddr)) | |||
| 201 | + | // We take the address and then dereference it to trick go vet from creating a possible misuse of unsafe.Pointer | |||
| 202 | + | ptr := *(*uintptr)(addr) | |||
| 203 | + | if ptr == 0 { | |||
| 204 | + | break | |||
| 205 | + | } | |||
| 206 | + | ret = append(ret, GoString(ptr)) | |||
| 207 | + | } | |||
| 208 | + | ||||
| 209 | + | return ret | |||
| 210 | + | } | |||
| 211 | + | ||||
| 161 | // GoString copies a char* to a Go string. | 212 | // GoString copies a char* to a Go string. | ||
| 162 | // This function was copied from purego | 213 | // This function was copied from purego | ||
| 163 | func GoString(c uintptr) string { | 214 | func GoString(c uintptr) string { | ||
M internal/gir/util/util.go +2 -38
| @@ -236,46 +236,10 @@ func PropertyVectorSet(notGLib bool) string { | |||
| 236 | 236 | } | |
| 237 | 237 | ||
| 238 | 238 | return prefix + `StrvGetType()) | |
| 239 | - | ||
| 240 | - | cStrBytes := make([][]byte, len(value)) | |
| 241 | - | cStrings := make([]uintptr, len(value)+1) | |
| 242 | - | for i, s := range value { | |
| 243 | - | cStrBytes[i] = make([]byte, len(s)+1) | |
| 244 | - | copy(cStrBytes[i], s) | |
| 245 | - | cStrBytes[i][len(s)] = 0 | |
| 246 | - | cStrings[i] = uintptr(unsafe.Pointer(&cStrBytes[i][0])) | |
| 247 | - | } | |
| 248 | - | cStrings[len(value)] = 0 | |
| 249 | - | ||
| 250 | - | v.SetBoxed(uintptr(unsafe.Pointer(&cStrings[0])))` | |
| 239 | + | v.SetBoxed(uintptr(unsafe.Pointer(core.ByteSlice(value))))` | |
| 251 | 240 | } | |
| 252 | 241 | ||
| 253 | 242 | // PropertyVectorGet returns the code for getting a vector property value | |
| 254 | 243 | func PropertyVectorGet() string { | |
| 255 | - | return `cStrvPtr := v.GetBoxed() | |
| 256 | - | if cStrvPtr == 0 { | |
| 257 | - | return nil | |
| 258 | - | } | |
| 259 | - | ||
| 260 | - | var result []string | |
| 261 | - | ptr := cStrvPtr | |
| 262 | - | for { | |
| 263 | - | strPtr := *(*uintptr)(unsafe.Pointer(ptr)) | |
| 264 | - | if strPtr == 0 { | |
| 265 | - | break | |
| 266 | - | } | |
| 267 | - | ||
| 268 | - | var length int | |
| 269 | - | for i := 0; ; i++ { | |
| 270 | - | if *(*byte)(unsafe.Pointer(strPtr + uintptr(i))) == 0 { | |
| 271 | - | length = i | |
| 272 | - | break | |
| 273 | - | } | |
| 274 | - | } | |
| 275 | - | ||
| 276 | - | bytes := unsafe.Slice((*byte)(unsafe.Pointer(strPtr)), length) | |
| 277 | - | result = append(result, string(bytes)) | |
| 278 | - | ptr += unsafe.Sizeof(uintptr(0)) | |
| 279 | - | } | |
| 280 | - | return result` | |
| 244 | + | return `return core.GoStringSlice(v.GetBoxed())` | |
| 281 | 245 | } | |
| @@ -236,46 +236,10 @@ func PropertyVectorSet(notGLib bool) string { | |||||
| 236 | } | 236 | } | ||
| 237 | 237 | ||||
| 238 | return prefix + `StrvGetType()) | 238 | return prefix + `StrvGetType()) | ||
| 239 | - | 239 | + | v.SetBoxed(uintptr(unsafe.Pointer(core.ByteSlice(value))))` | |
| 240 | - | cStrBytes := make([][]byte, len(value)) | |||
| 241 | - | cStrings := make([]uintptr, len(value)+1) | |||
| 242 | - | for i, s := range value { | |||
| 243 | - | cStrBytes[i] = make([]byte, len(s)+1) | |||
| 244 | - | copy(cStrBytes[i], s) | |||
| 245 | - | cStrBytes[i][len(s)] = 0 | |||
| 246 | - | cStrings[i] = uintptr(unsafe.Pointer(&cStrBytes[i][0])) | |||
| 247 | - | } | |||
| 248 | - | cStrings[len(value)] = 0 | |||
| 249 | - | ||||
| 250 | - | v.SetBoxed(uintptr(unsafe.Pointer(&cStrings[0])))` | |||
| 251 | } | 240 | } | ||
| 252 | 241 | ||||
| 253 | // PropertyVectorGet returns the code for getting a vector property value | 242 | // PropertyVectorGet returns the code for getting a vector property value | ||
| 254 | func PropertyVectorGet() string { | 243 | func PropertyVectorGet() string { | ||
| 255 | - | return `cStrvPtr := v.GetBoxed() | 244 | + | return `return core.GoStringSlice(v.GetBoxed())` |
| 256 | - | if cStrvPtr == 0 { | |||
| 257 | - | return nil | |||
| 258 | - | } | |||
| 259 | - | ||||
| 260 | - | var result []string | |||
| 261 | - | ptr := cStrvPtr | |||
| 262 | - | for { | |||
| 263 | - | strPtr := *(*uintptr)(unsafe.Pointer(ptr)) | |||
| 264 | - | if strPtr == 0 { | |||
| 265 | - | break | |||
| 266 | - | } | |||
| 267 | - | ||||
| 268 | - | var length int | |||
| 269 | - | for i := 0; ; i++ { | |||
| 270 | - | if *(*byte)(unsafe.Pointer(strPtr + uintptr(i))) == 0 { | |||
| 271 | - | length = i | |||
| 272 | - | break | |||
| 273 | - | } | |||
| 274 | - | } | |||
| 275 | - | ||||
| 276 | - | bytes := unsafe.Slice((*byte)(unsafe.Pointer(strPtr)), length) | |||
| 277 | - | result = append(result, string(bytes)) | |||
| 278 | - | ptr += unsafe.Sizeof(uintptr(0)) | |||
| 279 | - | } | |||
| 280 | - | return result` | |||
| 281 | } | 245 | } | ||
M pkg/core/core.go +2 -0
| @@ -4,6 +4,8 @@ import "github.com/jwijenbergh/puregotk/internal/core" | |||
| 4 | 4 | ||
| 5 | 5 | var ( | |
| 6 | 6 | GetPaths = core.GetPaths | |
| 7 | + | ByteSlice = core.ByteSlice | |
| 8 | + | GoStringSlice = core.GoStringSlice | |
| 7 | 9 | GoString = core.GoString | |
| 8 | 10 | SetPackageName = core.SetPackageName | |
| 9 | 11 | SetSharedLibraries = core.SetSharedLibraries | |
| @@ -4,6 +4,8 @@ import "github.com/jwijenbergh/puregotk/internal/core" | |||||
| 4 | 4 | ||||
| 5 | var ( | 5 | var ( | ||
| 6 | GetPaths = core.GetPaths | 6 | GetPaths = core.GetPaths | ||
| 7 | + | ByteSlice = core.ByteSlice | |||
| 8 | + | GoStringSlice = core.GoStringSlice | |||
| 7 | GoString = core.GoString | 9 | GoString = core.GoString | ||
| 8 | SetPackageName = core.SetPackageName | 10 | SetPackageName = core.SetPackageName | ||
| 9 | SetSharedLibraries = core.SetSharedLibraries | 11 | SetSharedLibraries = core.SetSharedLibraries | ||