From 735c7c4465a77d2953e9cb1328284e754f797db7 Mon Sep 17 00:00:00 2001 From: Stefan Majewsky Date: Mon, 5 Feb 2018 22:06:18 +0100 Subject: apparently having a private member is not enough --- account.go | 2 ++ container.go | 11 ++++++++++- headers.go | 27 +++++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/account.go b/account.go index 4438ce8..f4e8c07 100644 --- a/account.go +++ b/account.go @@ -117,6 +117,7 @@ func (a *Account) Invalidate() { // //A successful POST request implies Invalidate() since it may change metadata. func (a *Account) Update(headers AccountHeaders, opts *RequestOptions) error { + ensureInitializedByReflection(headers) _, err := Request{ Method: "POST", Headers: headers.ToHTTP(), @@ -137,6 +138,7 @@ func (a *Account) Update(headers AccountHeaders, opts *RequestOptions) error { // //A successful PUT request implies Invalidate() since it may change metadata. func (a *Account) Create(headers AccountHeaders, opts *RequestOptions) error { + ensureInitializedByReflection(headers) _, err := Request{ Method: "PUT", Headers: headers.ToHTTP(), diff --git a/container.go b/container.go index e3b95d8..cfc0eab 100644 --- a/container.go +++ b/container.go @@ -96,6 +96,7 @@ func (c *Container) Headers() (ContainerHeaders, error) { // //A successful POST request implies Invalidate() since it may change metadata. func (c *Container) Update(headers ContainerHeaders, opts *RequestOptions) error { + ensureInitializedByReflection(headers) _, err := Request{ Method: "POST", ContainerName: c.name, @@ -116,6 +117,7 @@ func (c *Container) Update(headers ContainerHeaders, opts *RequestOptions) error // //A successful PUT request implies Invalidate() since it may change metadata. func (c *Container) Create(headers ContainerHeaders, opts *RequestOptions) error { + ensureInitializedByReflection(headers) _, err := Request{ Method: "PUT", ContainerName: c.name, @@ -137,7 +139,14 @@ func (c *Container) Create(headers ContainerHeaders, opts *RequestOptions) error //This operation fails with http.StatusNotFound if the container does not exist. // //A successful DELETE request implies Invalidate(). -func (c *Container) Delete(headers ContainerHeaders, opts *RequestOptions) error { +func (c *Container) Delete(headers *ContainerHeaders, opts *RequestOptions) error { + if headers == nil { + h := NewContainerHeaders() + headers = &h + } else { + ensureInitializedByReflection(*headers) + } + _, err := Request{ Method: "DELETE", ContainerName: c.name, diff --git a/headers.go b/headers.go index 44d0607..2d81ddf 100644 --- a/headers.go +++ b/headers.go @@ -19,6 +19,7 @@ package schwift import ( + "fmt" "reflect" "github.com/majewsky/schwift/headers" @@ -29,6 +30,9 @@ import ( //request on the account, and will be sent by a PUT or POST request. The other //attributes allow type-safe access to well-known headers, as noted in the tags //next to each field. +// +//Follow the link on the Headers attribute for the documentation of the Get(), +//Set(), Del(), Clear() methods on this type. type AccountHeaders struct { headers.Headers BytesUsed headers.Uint64Readonly `schwift:"X-Account-Bytes-Used"` @@ -39,14 +43,18 @@ type AccountHeaders struct { TempURLKey headers.String `schwift:"X-Account-Meta-Temp-URL-Key"` TempURLKey2 headers.String `schwift:"X-Account-Meta-Temp-URL-Key-2"` //forbid initialization as struct literal (must use NewAccountHeaders) - private struct{} + initialized bool } //NewAccountHeaders prepares a new AccountHeaders instance. +// +//WARNING: Always use this function to construct AccountHeaders instances. +//Failure to do so will result in uncontrolled crashes! func NewAccountHeaders() AccountHeaders { var ah AccountHeaders ah.Headers = make(headers.Headers) initializeByReflection(&ah) + ah.initialized = true return ah } @@ -64,19 +72,26 @@ func (ah AccountHeaders) Validate() error { //request on the container, and will be sent by a PUT or POST request. The //other attributes allow type-safe access to well-known headers, as noted in //the tags next to each field. +// +//Follow the link on the Headers attribute for the documentation of the Get(), +//Set(), Del(), Clear() methods on this type. type ContainerHeaders struct { headers.Headers Metadata headers.Metadata `schwift:"X-Container-Meta-"` //TODO map well-known headers //forbid initialization as struct literal (must use NewContainerHeaders) - private struct{} + initialized bool } //NewContainerHeaders prepares a new ContainerHeaders instance. +// +//WARNING: Always use this function to construct ContainerHeaders instances. +//Failure to do so will result in uncontrolled crashes! func NewContainerHeaders() ContainerHeaders { var ch ContainerHeaders ch.Headers = make(headers.Headers) initializeByReflection(&ch) + ch.initialized = true return ch } @@ -122,6 +137,14 @@ func validateByReflection(value interface{}) error { }) } +func ensureInitializedByReflection(value interface{}) { + initialized := reflect.ValueOf(value).FieldByName("initialized").Bool() + if !initialized { + msg := "values of type %T MUST be initialized with the corresponding New...() function" + panic(fmt.Sprintf(msg, value, value)) + } +} + func foreachTaggedField(value interface{}, callback func(fieldPtr interface{}, info fieldInfo) error) error { rv := reflect.ValueOf(value).Elem() -- cgit v1.2.3