<commit_before>package optshttp

import (
  "net/http"
  "time"
  "github.com/gorilla/mux"
  "fmt"
  "strconv"
  "reflect"
  "unsafe"
  "strings"
)

const(
  flagForm = "form"
  flagPath = "path"
  flagInline = "inline"
)

func UnmarshalForm(req *http.Request, v interface{}) error {
  return unmarshalStruct(reflect.ValueOf(v).Elem(), flagForm, func(s string) string {return req.FormValue(s)})
}

func UnmarshalPath(req *http.Request, v interface{}) error {
  vars := mux.Vars(req)
  return unmarshalStruct(reflect.ValueOf(v).Elem(), flagPath, func(s string) string {return vars[s]})
}

type optsError struct{
  optType string
  optKey string
  optVal string
}

func (e *optsError) Error() string {
  return fmt.Sprintf("Invalid %s %s: %s", e.optType, e.optKey, e.optVal)
}

func unmarshalStruct(v reflect.Value, tagKey string, varLookup func(string) string) error {
  vt := v.Type()
  numField := vt.NumField()
  for i := 0; i < numField; i++ {
    field := vt.Field(i)
    if tagStr, ok := field.Tag.Lookup(tagKey); ok {
      if (len(tagStr) == 0) {
        continue
      }
      tagFields := strings.Split(tagStr, ",")
      if len(tagFields) > 1 {
        for _, flag := range tagFields[1:] {
          switch flag {
            case flagInline:
              if err := unmarshalStruct(v.Field(i), tagKey, varLookup); err != nil {
                return err
              }
          }
        }
      }
      if len(tagFields) > 0 && len(tagFields[0]) > 0 {
        formStr := varLookup(tagFields[0])
        if err := setValue(v.Field(i), tagFields[0], formStr); err != nil {
          return err
        }
      }
    }
  }
  return nil
}

var pStrType = reflect.TypeOf((*string)(nil))
var pIntType = reflect.TypeOf((*int)(nil))
var pUintType = reflect.TypeOf((*uint)(nil))
var timeType = reflect.TypeOf(time.Time{})
var pTimeType = reflect.PtrTo(timeType)

func setValue(v reflect.Value, formKey string, formStr string) error {
  switch v.Kind() {
    case reflect.String:
      v.SetString(formStr)
    case reflect.Int:
      if val, err := strconv.ParseInt(formStr, 10, 0); err != nil{
        return &optsError{"integer", formKey, formStr}     
      } else {
        v.SetInt(val)
      }
    case reflect.Uint:
      if val, err := strconv.ParseUint(formStr, 10, 0); err != nil{
        return &optsError{"unsigned integer", formKey, formStr}     
      } else {
        v.SetUint(val)<commit_msg>Do not try to parse empty fields<commit_after>package optshttp

import (
  "net/http"
  "time"
  "github.com/gorilla/mux"
  "fmt"
  "strconv"
  "reflect"
  "unsafe"
  "strings"
)

const(
  flagForm = "form"
  flagPath = "path"
  flagInline = "inline"
)

func UnmarshalForm(req *http.Request, v interface{}) error {
  return unmarshalStruct(reflect.ValueOf(v).Elem(), flagForm, func(s string) string {return req.FormValue(s)})
}

func UnmarshalPath(req *http.Request, v interface{}) error {
  vars := mux.Vars(req)
  return unmarshalStruct(reflect.ValueOf(v).Elem(), flagPath, func(s string) string {return vars[s]})
}

type optsError struct{
  optType string
  optKey string
  optVal string
}

func (e *optsError) Error() string {
  return fmt.Sprintf("Invalid %s %s: %s", e.optType, e.optKey, e.optVal)
}

func unmarshalStruct(v reflect.Value, tagKey string, varLookup func(string) string) error {
  vt := v.Type()
  numField := vt.NumField()
  for i := 0; i < numField; i++ {
    field := vt.Field(i)
    if tagStr, ok := field.Tag.Lookup(tagKey); ok {
      if (len(tagStr) == 0) {
        continue
      }
      tagFields := strings.Split(tagStr, ",")
      if len(tagFields) > 1 {
        for _, flag := range tagFields[1:] {
          switch flag {
            case flagInline:
              if err := unmarshalStruct(v.Field(i), tagKey, varLookup); err != nil {
                return err
              }
          }
        }
      }
      if len(tagFields) > 0 && len(tagFields[0]) > 0 {
        if formStr := varLookup(tagFields[0]); len(formStr) > 0 {
          if err := setValue(v.Field(i), tagFields[0], tagFields[0]); err != nil {
            return err
          }
        }
      }
    }
  }
  return nil
}

var pStrType = reflect.TypeOf((*string)(nil))
var pIntType = reflect.TypeOf((*int)(nil))
var pUintType = reflect.TypeOf((*uint)(nil))
var timeType = reflect.TypeOf(time.Time{})
var pTimeType = reflect.PtrTo(timeType)

func setValue(v reflect.Value, formKey string, formStr string) error {
  switch v.Kind() {
    case reflect.String:
      v.SetString(formStr)
    case reflect.Int:
      if val, err := strconv.ParseInt(formStr, 10, 0); err != nil{
        return &optsError{"integer", formKey, formStr}     
      } else {
        v.SetInt(val)
      }
    case reflect.Uint:
      if val, err := strconv.ParseUint(formStr, 10, 0); err != nil{
        return &optsError{"unsigned integer", formKey, formStr}     
      } else {
        v.SetUint(val)
{'fraction_non_alphanumeric': 0.1431200163565733, 'fraction_numerical': 0.006542629319157636, 'mean_word_length': 2.7088703563305536, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1960649', 'n_tokens_mistral': 1694, 'n_tokens_neox': 1653, 'n_words': 410}