diff --git a/internals/cookies/encoding.go b/internals/cookies/encoding.go index dafa8dc..47d3496 100644 --- a/internals/cookies/encoding.go +++ b/internals/cookies/encoding.go @@ -1,7 +1,7 @@ package cookies import ( - "errors" + e "errors" "math/bits" "net/http" "reflect" @@ -21,31 +21,22 @@ func Marshal[T any](c TypedCookie[T]) (http.Cookie, error) { } v := []string{} - for i := 0; i < rv.NumField(); i++ { - f := rv.Type().Field(i) - fv := rv.FieldByName(f.Name) - - if fv.Kind() == reflect.Pointer { - fv = fv.Elem() - } - - if !fv.IsValid() { - return http.Cookie{}, errors.New("No such field in object: " + f.Name) - } - - t := f.Tag.Get("cookie") + err := forEachField(&rv, func(fv *reflect.Value, ft *reflect.StructField) error { + t := ft.Tag.Get("cookie") if t == "" { - t = f.Name + t = ft.Name } tv := strings.Split(t, ",") - value, err := encodeString(fv) + value, err := encodeString(*fv) if err != nil { - return http.Cookie{}, errors.Join(errors.New("Unsupportted type in struct: "+fv.Kind().String()), err) + return e.Join(e.New("Unsupported type in struct: "+fv.Kind().String()), err) } v = append(v, tv[0]+":"+value) - } + + return nil + }) return http.Cookie{ Name: c.Name, @@ -58,19 +49,22 @@ func Marshal[T any](c TypedCookie[T]) (http.Cookie, error) { Secure: c.Secure, HttpOnly: c.HttpOnly, SameSite: c.SameSite, - }, nil + }, err } func Unmarshal[T any](data http.Cookie, v *TypedCookie[T]) error { if reflect.ValueOf(v).Kind() != reflect.Pointer { - return errors.New("`v` is not a pointer: " + reflect.ValueOf(v).Kind().String()) + return e.New("`v` is not a pointer: " + reflect.ValueOf(v).Kind().String()) + } + if reflect.TypeOf(&v.TypedValue) == nil { + return e.New("TypedCookie.TypedValue is not a valid struct type") } m := make(map[string]string) for _, pair := range strings.Split(data.Value, "|") { pairV := strings.Split(pair, ":") if len(pairV) == 0 { - return errors.New("Error trying to decode cookie value:\n" + data.Value + "\n\nMissing \":\" pair in first slice") + return e.New("Error trying to decode cookie value:\n" + data.Value + "\n\nMissing \":\" pair in first slice") } key := pairV[0] @@ -85,55 +79,65 @@ func Unmarshal[T any](data http.Cookie, v *TypedCookie[T]) error { m[key] = value } - tt := reflect.TypeOf(&v.TypedValue) tv := reflect.ValueOf(&v.TypedValue) - if tt == nil { - return errors.New("TypedCookie.TypedValue is not a valid struct{} type") - } - - if tt.Kind() == reflect.Pointer { - tt = tt.Elem() - } if tv.Kind() == reflect.Pointer { tv = tv.Elem() } - for i := 0; i < tt.NumField(); i++ { - f := tt.Field(i) - fv := tv.FieldByName(f.Name) - if fv.Kind() == reflect.Pointer { - fv = fv.Elem() - } - - if !fv.IsValid() { - return errors.New("No such field in object: " + f.Name) - } - if !fv.CanSet() { - return errors.New("Cannot set value of such field in object: " + f.Name) - } - - t := f.Tag.Get("cookie") + err := forEachField(&tv, func(fv *reflect.Value, ft *reflect.StructField) error { + t := ft.Tag.Get("cookie") if t == "" { - t = f.Name + t = ft.Name } tk := strings.Split(t, ",")[0] final, err := decodeString(m[tk], fv.Kind()) if err != nil { - return errors.Join(errors.New("Unsupportted type in struct: "+fv.Kind().String()), err) + return e.Join(e.New("Unsupported type in struct: "+fv.Kind().String()), err) } - if strings.Contains(strings.ToLower(fv.Kind().String()), "complex") { + kStr := strings.ToLower(fv.Kind().String()) + if strings.Contains(kStr, "complex") { fv.SetComplex(final.(complex128)) - } else if strings.Contains(strings.ToLower(fv.Kind().String()), "uint") { + + } else if strings.Contains(kStr, "uint") { fv.SetUint(final.(uint64)) - } else if strings.Contains(strings.ToLower(fv.Kind().String()), "int") { + + } else if strings.Contains(kStr, "int") { fv.SetInt(final.(int64)) + } else { fv.Set(reflect.ValueOf(final)) } + + return nil + }) + + return err +} + +func forEachField(v *reflect.Value, callback func(fv *reflect.Value, ft *reflect.StructField) error) (err error) { + t := v.Type() + + for i := 0; i < t.NumField(); i++ { + ft := t.Field(i) + fv := v.FieldByName(ft.Name) + + if fv.Kind() == reflect.Pointer { + fv = fv.Elem() + } + + if !fv.IsValid() { + return e.New("No such field: " + ft.Name) + } + + err = callback(&fv, &ft) + if err != nil { + return e.Join(e.New("Error while looping through value"), err) + } } - return nil + + return err } func encodeString(v reflect.Value) (string, error) { @@ -161,7 +165,7 @@ func encodeString(v reflect.Value) (string, error) { return v.String(), nil default: - return "", errors.ErrUnsupported + return "", e.ErrUnsupported } } @@ -209,7 +213,7 @@ func decodeString(v string, k reflect.Kind) (any, error) { final = v default: - return nil, errors.ErrUnsupported + return nil, e.ErrUnsupported } return final, err