package secrets import ( "fmt" "os" "reflect" "strconv" ) func parseSetInt[T int | int8 | int16 | int32 | int64](f reflect.Value, v string, size int) error { iv, err := strconv.ParseInt(v, 0, size) if err != nil { return err } f.Set(reflect.ValueOf(T(iv))) return nil } func parseSetUint[T uint | uint8 | uint16 | uint32 | uint64](f reflect.Value, v string, size int) error { iv, err := strconv.ParseUint(v, 0, size) if err != nil { return err } f.Set(reflect.ValueOf(T(iv))) return nil } func parseSetFloat[T float32 | float64](f reflect.Value, v string, size int) error { iv, err := strconv.ParseFloat(v, size) if err != nil { return err } f.Set(reflect.ValueOf(T(iv))) return nil } func UnmarshalEnvironment(into any) error { t := reflect.TypeOf(into).Elem() o := reflect.ValueOf(into).Elem() for i := 0; i < t.NumField(); i++ { tf := t.Field(i) f := o.FieldByName(tf.Name) envName := tf.Tag.Get("env") if envName == "" { continue } envValue, ok := os.LookupEnv(envName) if !ok { continue } switch typ := f.Type().Kind(); typ { case reflect.Bool: b, err := strconv.ParseBool(envValue) if err != nil { return err } f.Set(reflect.ValueOf(b)) case reflect.String: f.Set(reflect.ValueOf(envValue)) case reflect.Int: if err := parseSetInt[int](f, envValue, 64); err != nil { return err } case reflect.Int8: if err := parseSetInt[int8](f, envValue, 8); err != nil { return err } case reflect.Int16: if err := parseSetInt[int16](f, envValue, 16); err != nil { return err } case reflect.Int32: if err := parseSetInt[int32](f, envValue, 32); err != nil { return err } case reflect.Int64: if err := parseSetInt[int64](f, envValue, 64); err != nil { return err } case reflect.Uint: if err := parseSetUint[uint](f, envValue, 64); err != nil { return err } case reflect.Uint8: if err := parseSetUint[uint8](f, envValue, 8); err != nil { return err } case reflect.Uint16: if err := parseSetUint[uint16](f, envValue, 16); err != nil { return err } case reflect.Uint32: if err := parseSetUint[uint32](f, envValue, 32); err != nil { return err } case reflect.Uint64: if err := parseSetUint[uint64](f, envValue, 64); err != nil { return err } case reflect.Float32: if err := parseSetFloat[float32](f, envValue, 32); err != nil { return err } case reflect.Float64: if err := parseSetFloat[float64](f, envValue, 64); err != nil { return err } default: return fmt.Errorf("UnmarshalEnvironment: unabled to handle type: %s", typ) } } return nil }