generic way to build options from a struct
diff --git a/params.go b/params.go
index f11a29d..da4ad94 100644
--- a/params.go
+++ b/params.go
@@ -1,5 +1,14 @@
 package gophercloud
 
+import (
+	"fmt"
+	"net/url"
+	"reflect"
+	"strconv"
+	"strings"
+	"time"
+)
+
 // MaybeString takes a string that might be a zero-value, and either returns a
 // pointer to its address or a nil value (i.e. empty pointer). This is useful
 // for converting zero values in options structs when the end-user hasn't
@@ -11,3 +20,138 @@
 	}
 	return nil
 }
+
+var t time.Time
+
+func isZero(v reflect.Value) bool {
+	switch v.Kind() {
+	case reflect.Func, reflect.Map, reflect.Slice:
+		return v.IsNil()
+	case reflect.Array:
+		z := true
+		for i := 0; i < v.Len(); i++ {
+			z = z && isZero(v.Index(i))
+		}
+		return z
+	case reflect.Struct:
+		if v.Type() == reflect.TypeOf(t) {
+			if v.Interface().(time.Time).IsZero() {
+				return true
+			}
+			return false
+		}
+		z := true
+		for i := 0; i < v.NumField(); i++ {
+			z = z && isZero(v.Field(i))
+		}
+		return z
+	}
+	// Compare other types directly:
+	z := reflect.Zero(v.Type())
+	return v.Interface() == z.Interface()
+}
+
+func BuildQueryString(opts interface{}) (string, error) {
+	optsValue := reflect.ValueOf(opts)
+	if optsValue.Kind() == reflect.Ptr {
+		optsValue = optsValue.Elem()
+	}
+
+	optsType := reflect.TypeOf(opts)
+	if optsType.Kind() == reflect.Ptr {
+		optsType = optsType.Elem()
+	}
+
+	optsSlice := make([]string, 0)
+	if optsValue.Kind() == reflect.Struct {
+		for i := 0; i < optsValue.NumField(); i++ {
+			v := optsValue.Field(i)
+			f := optsType.Field(i)
+			qTag := f.Tag.Get("q")
+
+			// if the field has a 'q' tag, it goes in the query string
+			if qTag != "" {
+				tags := strings.Split(qTag, ",")
+
+				// if the field is set, add it to the slice of query pieces
+				if !isZero(v) {
+					switch v.Kind() {
+					case reflect.String:
+						optsSlice = append(optsSlice, tags[0]+"="+v.String())
+					case reflect.Int:
+						optsSlice = append(optsSlice, tags[0]+"="+strconv.FormatInt(v.Int(), 10))
+					case reflect.Bool:
+						optsSlice = append(optsSlice, tags[0]+"="+strconv.FormatBool(v.Bool()))
+					}
+				} else {
+					// Otherwise, the field is not set.
+					if len(tags) == 2 && tags[1] == "required" {
+						// And the field is required. Return an error.
+						return "", fmt.Errorf("Required query parameter not set.")
+					}
+				}
+			}
+
+		}
+		// URL encode the string for safety.
+		s := url.QueryEscape(strings.Join(optsSlice, "&"))
+		if s != "" {
+			s = "?" + s
+		}
+		return s, nil
+	}
+	// Return an error if the underlying type of 'opts' isn't a struct.
+	return "", fmt.Errorf("Options type is not a struct.")
+}
+
+func BuildRequestBody(opts interface{}) (map[string]interface{}, error) {
+	return nil, nil
+}
+
+func BuildHeaders(opts interface{}) (map[string]string, error) {
+	optsValue := reflect.ValueOf(opts)
+	if optsValue.Kind() == reflect.Ptr {
+		optsValue = optsValue.Elem()
+	}
+
+	optsType := reflect.TypeOf(opts)
+	if optsType.Kind() == reflect.Ptr {
+		optsType = optsType.Elem()
+	}
+
+	optsMap := make(map[string]string)
+	if optsValue.Kind() == reflect.Struct {
+		for i := 0; i < optsValue.NumField(); i++ {
+			v := optsValue.Field(i)
+			f := optsType.Field(i)
+			hTag := f.Tag.Get("h")
+
+			// if the field has a 'h' tag, it goes in the header
+			if hTag != "" {
+				tags := strings.Split(hTag, ",")
+
+				// if the field is set, add it to the slice of query pieces
+				if !isZero(v) {
+					switch v.Kind() {
+					case reflect.String:
+						optsMap[tags[0]] = v.String()
+					case reflect.Int:
+						optsMap[tags[0]] = strconv.FormatInt(v.Int(), 10)
+					case reflect.Bool:
+						optsMap[tags[0]] = strconv.FormatBool(v.Bool())
+					}
+				} else {
+					// Otherwise, the field is not set.
+					if len(tags) == 2 && tags[1] == "required" {
+						// And the field is required. Return an error.
+						return optsMap, fmt.Errorf("Required header not set.")
+					}
+				}
+			}
+
+		}
+		return optsMap, nil
+	}
+	// Return an error if the underlying type of 'opts' isn't a struct.
+	return optsMap, fmt.Errorf("Options type is not a struct.")
+}