hijacker.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  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. // ErrHandled can be returned from a hijacker to specify
  18. // that the hijacker handled the write operation itself,
  19. // therefore pio does not need to do anything else.
  20. ErrHandled = errors.New("handled")
  21. )
  22. var cPool = sync.Pool{New: func() interface{} { return &Ctx{} }}
  23. func acquireCtx(v interface{}, printer *Printer) *Ctx {
  24. ctx := cPool.Get().(*Ctx)
  25. ctx.Printer = printer
  26. ctx.Value = v
  27. ctx.marshalResult.b = ctx.marshalResult.b[0:0]
  28. ctx.marshalResult.err = nil
  29. ctx.canceled = false
  30. ctx.continueToNext = false
  31. return ctx
  32. }
  33. func releaseCtx(ctx *Ctx) {
  34. cPool.Put(ctx)
  35. }
  36. // Ctx is the current context of the Printer's hijacker,
  37. // should not be used inside goroutines,
  38. // exiting this hijacker allows the Printer to continue its execution.
  39. type Ctx struct {
  40. // Printer is the current Printer which this ctx is owned by.
  41. Printer *Printer
  42. // Value is the argument passed to the `Printer#Print`.
  43. //
  44. // Value shoult not be changed.
  45. Value interface{}
  46. marshalResult struct {
  47. b []byte
  48. err error
  49. }
  50. continueToNext bool
  51. canceled bool
  52. }
  53. // MarshalValue marshals the `Value`
  54. // and skips the marshal operation on the `Printer#Print` state.
  55. //
  56. // Remember that if `MarshalValue` called after a `SetResult`
  57. // then it will not operate a marshaling and return the
  58. // stored result instead.
  59. func (ctx *Ctx) MarshalValue() ([]byte, error) {
  60. if len(ctx.marshalResult.b) > 0 {
  61. return ctx.marshalResult.b, ctx.marshalResult.err
  62. }
  63. if ctx.Printer.marshal == nil {
  64. return nil, ErrSkipped
  65. }
  66. b, err := ctx.Printer.marshal(ctx.Value)
  67. ctx.marshalResult.b = b
  68. ctx.marshalResult.err = err
  69. return b, err
  70. }
  71. // Store bypasses the marshaler and sets the result explicitly.
  72. // If any of the next hijackers try to call the `MarshalValue` then it will
  73. // return the results that had set here.
  74. func (ctx *Ctx) Store(result []byte, err error) {
  75. ctx.marshalResult.b = result
  76. ctx.marshalResult.err = err
  77. }
  78. // Cancel cancels the printing of this `Value`.
  79. func (ctx *Ctx) Cancel() {
  80. ctx.canceled = true
  81. }
  82. // Next allows to continue to the next hijacker,if available, when this hijacker finished.
  83. func (ctx *Ctx) Next() {
  84. ctx.continueToNext = true
  85. }