diff --git a/error/chain-error.go b/error/chain-error.go index d427330..e084ced 100644 --- a/error/chain-error.go +++ b/error/chain-error.go @@ -3,41 +3,33 @@ package error import ( - "memar/protocol" + error_p "memar/error/protocol" ) +// PastChain unwrap an error and return last chain of error. +func PastChain(err error_p.Error) (last error_p.Error) { + var chainedError, ok = err.(error_p.Chain) + if ok { + return chainedError.PastChain() + } + return +} + // NewChain wrap an error and additional information usually use in logging to save more details about error. -func NewChain(err *Error, info string) (ce *ChainError) { - if err == nil { +func NewChain(err error_p.Error, chain error_p.Error) (ce *ChainError) { + if err == nil || chain == nil { return } return &ChainError{ - Err: err, - info: info, + Error: err, + chain: chain, } } // ChainError is a extended implementation of Error to carry custom details along error. type ChainError struct { - *Err - info string -} - -func (ce *ChainError) PastChain() protocol.Error { return ce.Err } - -//memar:impl memar/protocol.Stringer -func (ce *ChainError) ToString() string { - return "\n" + ce.Err.ToString() + "\n Chain Info: " + ce.info + error_p.Error + chain error_p.Error } -func (ce *ChainError) FromString(s string) (err protocol.Error) { - // TODO::: - return -} - -// Go compatibility methods. Unwrap provides compatibility for Go 1.13 error chains. -func (ce *ChainError) Error() string { return ce.ToString() } -func (ce *ChainError) Cause() error { return ce.Err } -func (ce *ChainError) Unwrap() error { return ce.Err } -// func (ce *ChainError) Is(error) bool -// func (ce *ChainError) As(any) bool +func (ce *ChainError) PastChain() error_p.Error { return ce.chain } diff --git a/error/error-type.go b/error/error-type.go index bc1ecea..0aab60b 100644 --- a/error/error-type.go +++ b/error/error-type.go @@ -3,21 +3,23 @@ package error import ( - "memar/protocol" + error_p "memar/error/protocol" ) -type ErrorType protocol.ErrorType - -func (et *ErrorType) Set(errorType protocol.ErrorType) { *et |= ErrorType(errorType) } -func (et *ErrorType) Unset(errorType protocol.ErrorType) { *et &= ^ErrorType(errorType) } -func (et ErrorType) Check(errorType protocol.ErrorType) bool { - return errorType&protocol.ErrorType(et) == errorType +//memar:impl memar/error/protocol.Internal +func IsInternal(err error_p.Error) bool { + var interErr, ok = err.(error_p.Internal) + return ok && interErr.Internal() } -func (et Error) Internal() bool { return et.Check(protocol.ErrorType_Internal) } -func (et Error) Temporary() bool { return et.Check(protocol.ErrorType_Temporary) } -func (et Error) Timeout() bool { return et.Check(protocol.ErrorType_Timeout) } +//memar:impl memar/error/protocol.Temporary +func IsTemporary(err error_p.Error) bool { + var tempErr, ok = err.(error_p.Temporary) + return ok && tempErr.Temporary() +} -func (et *Error) SetInternal() { et.Set(protocol.ErrorType_Internal) } -func (et *Error) SetTemporary() { et.Set(protocol.ErrorType_Temporary) } -func (et *Error) SetTimeout() { et.Set(protocol.ErrorType_Timeout) } +//memar:impl memar/error/protocol.Timeout +func IsTimeout(err error_p.Error) bool { + var timeErr, ok = err.(error_p.Timeout) + return ok && timeErr.Timeout() +} diff --git a/error/error.go b/error/error.go index 5e0f635..1eb2334 100644 --- a/error/error.go +++ b/error/error.go @@ -3,58 +3,20 @@ package error import ( - "memar/datatype" - "memar/mediatype" - "memar/protocol" + error_p "memar/error/protocol" ) -// Err is the same as the Error. -// Use this type when embed in other struct to solve field & method same name problem(Error struct and Error() method) to satisfy interfaces. -type Err = Error - -// Error implements protocol.Error -type Error struct { - ErrorType - - mediatype.MT - datatype.DataType -} - -// Init initialize Error that implement protocol.Error -// Never change MediaType due to it adds unnecessary complicated troubleshooting errors on SDK. -// -//memar:impl memar/protocol.ObjectLifeCycle -func (e *Error) Init(mediatype string) (err protocol.Error) { - err = e.MT.Init(mediatype) - // if err != nil { - // return - // } - return -} - -// Equal compare two Error. -func (e *Error) Equal(err protocol.Error) bool { - if e == nil && err == nil { +// IsEqual compare two Error. +// Suggest to add more logic to Error.Equal() logic such as chain situation! +func IsEqual(base, with error_p.Error) bool { + if base == nil && with == nil { return true } - if e != nil && err != nil && e.ID() == err.ID() { + if base != nil && + with != nil && + base.MediaType() == with.MediaType() && + base.DataTypeID() == with.DataTypeID() { return true } - // TODO::: check err as chain error return false } - -func (e *Error) Type() protocol.ErrorType { return protocol.ErrorType(e.ErrorType) } -func (e *Error) CheckType(et protocol.ErrorType) bool { return e.ErrorType.Check(et) } - -func (e *Error) Notify() { - // TODO::: -} - -// Go compatibility methods. Unwrap provides compatibility for Go 1.13 error chains. -func (e *Error) Error() string { return e.MT.MediaType() } -func (e *Error) Cause() error { return nil } -func (e *Error) Unwrap() error { return nil } - -// func (e *Error) Is(error) bool -// func (e *Error) As(any) bool diff --git a/error/protocol/error.go b/error/protocol/error.go index d1d0642..0363667 100644 --- a/error/protocol/error.go +++ b/error/protocol/error.go @@ -5,21 +5,24 @@ package error_p import ( // primitive_p "memar/computer/language/primitive/protocol" datatype_p "memar/datatype/protocol" + mediatype_p "memar/mediatype/protocol" ) // Error is base behaviors that any Error capsule must implement. // -// It is similar to opaque error model describe here: https://dave.cheney.net/paste/gocon-spring-2016.pdf -// or this RFC: https://tools.ietf.org/html/rfc7807 +// Other suggestions: +// - opaque error model: https://dave.cheney.net/paste/gocon-spring-2016.pdf +// - RFC7807: https://tools.ietf.org/html/rfc7807 +// - https://doc.rust-lang.org/stable/std/error/trait.Error.html type Error interface { datatype_p.DataType + mediatype_p.MediaType - // Can't un-comment below due to Golang import cycle problem, So add it manually! + // Can't un-comment below due to Golang import cycle problem, So add it manually. // primitive_p.Equivalence[Error] Equal(with Error) bool // ADT - // MediaType // Below methods comment in favor of log_p.Event_Message interface. // Error() string diff --git a/error/protocol/gui.go b/error/protocol/gui.go index fc75fdd..b191534 100644 --- a/error/protocol/gui.go +++ b/error/protocol/gui.go @@ -2,6 +2,10 @@ package error_p +// GUI indicate how Error capsule must act in GUI applications. +// +// GUI can use also in CLI apps by e.g. use `//go:build gui` tag, +// But strongly suggest DON'T think in this way and just use `Log` concept type GUI interface { // Notify error to user by graphic, sound and vibration (Haptic Feedback) Notify() diff --git a/error/protocol/optional.go b/error/protocol/optional.go index c0ff022..db75e1b 100644 --- a/error/protocol/optional.go +++ b/error/protocol/optional.go @@ -5,6 +5,14 @@ package error_p // Belows are some other error behaviors that Errors capsule CAN implement, // but any error package can introduce new behaviors for any purpose. +// Chian errors can use in situation that error occurred but can't handle in that layer and +// Upper layer also can't handle it directly and decide to log it! +// Use chain errors to return multiple error to caller and +// Usually caller log them and return another error to caller that almost always SDK client e.g. GUI, Apps, ... +type Chain interface { + PastChain() (last Error) +} + type Internal interface { // Who cause the error? // Internal : means calling process logic has runtime bugs like HTTP server error status codes ( 500 – 599 ). diff --git a/error/util.go b/error/util.go index dde8334..800557e 100644 --- a/error/util.go +++ b/error/util.go @@ -3,20 +3,17 @@ package error import ( - "memar/protocol" + error_p "memar/error/protocol" ) -func ToGoError(err protocol.Error) error { +func ToGoError(err error_p.Error) error { if err == nil { return nil } - var exErr = err.(*Error) - if exErr != nil { - return exErr - } - - return &errorString{msg: err.ToString()} + var errStr errorString + errStr.msg = err.Summary() + return &errStr } // errorString is a trivial implementation of error. @@ -26,15 +23,16 @@ type errorString struct { func (e *errorString) Error() string { return e.msg } -func ToError(err error) protocol.Error { +func ToError(err error) error_p.Error { if err == nil { return nil } - var exErr = err.(*Error) + var exErr = err.(error_p.Error) if exErr != nil { return exErr } + // TODO::: return nil }