hijacker.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package pio
  2. import (
  3. "errors"
  4. "sync"
  5. )
  6. // Hijacker is the signature implemented by callers
  7. // that want to hijack the Print method.
  8. //
  9. // Look `Printer#Hijack` for more.
  10. type Hijacker func(*Ctx)
  11. var (
  12. // ErrCanceled is returned when a hijacker canceled a specific print action.
  13. ErrCanceled = errors.New("canceled")
  14. // ErrSkipped it returned from marshaler or hijacker
  15. // when the content should be skipped and printer should avoid printing it.
  16. ErrSkipped = errors.New("skipped")
  17. )
  18. var cPool = sync.Pool{New: func() interface{} { return &Ctx{} }}
  19. func acquireCtx(v interface{}, printer *Printer) *Ctx {
  20. ctx := cPool.Get().(*Ctx)
  21. ctx.Printer = printer
  22. ctx.Value = v
  23. ctx.marshalResult.b = ctx.marshalResult.b[0:0]
  24. ctx.marshalResult.err = nil
  25. ctx.canceled = false
  26. ctx.continueToNext = false
  27. return ctx
  28. }
  29. func releaseCtx(ctx *Ctx) {
  30. cPool.Put(ctx)
  31. }
  32. // Ctx is the current context of the Printer's hijacker,
  33. // should not be used inside goroutines,
  34. // exiting this hijacker allows the Printer to continue its execution.
  35. type Ctx struct {
  36. // Printer is the current Printer which this ctx is owned by.
  37. Printer *Printer
  38. // Value is the argument passed to the `Printer#Print`.
  39. //
  40. // Value shoult not be changed.
  41. Value interface{}
  42. marshalResult struct {
  43. b []byte
  44. err error
  45. }
  46. continueToNext bool
  47. canceled bool
  48. }
  49. // MarshalValue marshals the `Value`
  50. // and skips the marshal operation on the `Printer#Print` state.
  51. //
  52. // Remember that if `MarshalValue` called after a `SetResult`
  53. // then it will not operate a marshaling and return the
  54. // stored result instead.
  55. func (ctx *Ctx) MarshalValue() ([]byte, error) {
  56. if len(ctx.marshalResult.b) > 0 {
  57. return ctx.marshalResult.b, ctx.marshalResult.err
  58. }
  59. if ctx.Printer.marshal == nil {
  60. return nil, ErrSkipped
  61. }
  62. b, err := ctx.Printer.marshal(ctx.Value)
  63. ctx.marshalResult.b = b
  64. ctx.marshalResult.err = err
  65. return b, err
  66. }
  67. // Store bypasses the marshaler and sets the result explicitly.
  68. // If any of the next hijackers try to call the `MarshalValue` then it will
  69. // return the results that had set here.
  70. func (ctx *Ctx) Store(result []byte, err error) {
  71. ctx.marshalResult.b = result
  72. ctx.marshalResult.err = err
  73. }
  74. // Cancel cancels the printing of this `Value`.
  75. func (ctx *Ctx) Cancel() {
  76. ctx.canceled = true
  77. }
  78. // Next allows to continue to the next hijacker,if available, when this hijacker finished.
  79. func (ctx *Ctx) Next() {
  80. ctx.continueToNext = true
  81. }