libpostal/libpostal.go

136 lines
3.4 KiB
Go
Raw Permalink Normal View History

2026-08-08 08:50:11 -04:00
/*
The functions in this file are unexported to ensure safe use through the Parser.
*/
package libpostal
//#cgo LDFLAGS: -lpostal
//#include <libpostal/libpostal.h>
import "C"
import (
"fmt"
"strings"
"unsafe"
)
func setup() bool {
response := C.libpostal_setup()
return bool(response)
}
func setupDataDir(datadir string) bool {
datadir_cstr := C.CString(datadir)
response := C.libpostal_setup_datadir(datadir_cstr)
C.free(unsafe.Pointer(datadir_cstr))
return bool(response)
}
func tearDown() {
C.libpostal_teardown()
}
func setupParser() bool {
response := C.libpostal_setup_parser()
return bool(response)
}
func setupParserDataDir(datadir string) bool {
datadir_cstr := C.CString(datadir)
response := C.libpostal_setup_parser_datadir(datadir_cstr)
C.free(unsafe.Pointer(&datadir_cstr))
return bool(response)
}
func tearDownParser() {
C.libpostal_teardown_parser()
}
func setupLanguageClassifier() bool {
response := C.libpostal_setup_language_classifier()
return bool(response)
}
func setupLanguageClassifierDataDir(datadir string) bool {
datadir_cstr := C.CString(datadir)
response := C.libpostal_setup_language_classifier_datadir(datadir_cstr)
C.free(unsafe.Pointer(datadir_cstr))
return bool(response)
}
func tearDownLanguageClassifier() {
C.libpostal_teardown_language_classifier()
}
type AddressParserOptions struct {
Language string
Country string
}
func (goOpts AddressParserOptions) toC() (C.libpostal_address_parser_options_t, func()) {
cOpts := C.libpostal_get_address_parser_default_options()
var allocations []unsafe.Pointer
if goOpts.Language != "" {
cLang := C.CString(goOpts.Language)
cOpts.language = cLang
allocations = append(allocations, unsafe.Pointer(cLang))
}
if goOpts.Country != "" {
cCountry := C.CString(goOpts.Country)
cOpts.country = cCountry
allocations = append(allocations, unsafe.Pointer(cCountry))
}
cleanup := func() {
for _, ptr := range allocations {
C.free(ptr)
}
}
return cOpts, cleanup
}
func GetDefaultAddressParserOptions() AddressParserOptions {
cOpts := C.libpostal_get_address_parser_default_options()
return AddressParserOptions{
Language: C.GoString(cOpts.language),
Country: C.GoString(cOpts.country),
}
}
func parseAddress(addressToParse string, options AddressParserOptions) (Address, error) {
address_cstr := C.CString(addressToParse)
defer C.free(unsafe.Pointer(address_cstr))
cOpts, cleanup := options.toC()
defer cleanup()
var address Address
response := C.libpostal_parse_address(address_cstr, cOpts)
defer C.libpostal_address_parser_response_destroy(response)
labelsSlice := unsafe.Slice(response.labels, int(response.num_components))
componentSlice := unsafe.Slice(response.components, int(response.num_components))
for i := range int(response.num_components) {
label := C.GoString(labelsSlice[i])
component := C.GoString(componentSlice[i])
switch label {
case "house_number":
address.HouseNumber = strings.Clone(component)
case "road":
address.Road = strings.Clone(component)
case "city":
address.City = strings.Clone(component)
case "state":
address.State = strings.Clone(component)
case "postcode":
address.PostCode = strings.Clone(component)
default:
return Address{}, fmt.Errorf("unrecognized label: %s (%s)", label, component)
}
}
// is the Address valid?
if err := address.Invalid(); err != nil {
return Address{}, err
}
return address, nil
}