Don Newton | 379ae25 | 2019-04-01 12:17:06 -0400 | [diff] [blame^] | 1 | // Copyright (C) MongoDB, Inc. 2017-present. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 4 | // not use this file except in compliance with the License. You may obtain |
| 5 | // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 |
| 6 | |
| 7 | package bsonrw |
| 8 | |
| 9 | import ( |
| 10 | "fmt" |
| 11 | ) |
| 12 | |
| 13 | type mode int |
| 14 | |
| 15 | const ( |
| 16 | _ mode = iota |
| 17 | mTopLevel |
| 18 | mDocument |
| 19 | mArray |
| 20 | mValue |
| 21 | mElement |
| 22 | mCodeWithScope |
| 23 | mSpacer |
| 24 | ) |
| 25 | |
| 26 | func (m mode) String() string { |
| 27 | var str string |
| 28 | |
| 29 | switch m { |
| 30 | case mTopLevel: |
| 31 | str = "TopLevel" |
| 32 | case mDocument: |
| 33 | str = "DocumentMode" |
| 34 | case mArray: |
| 35 | str = "ArrayMode" |
| 36 | case mValue: |
| 37 | str = "ValueMode" |
| 38 | case mElement: |
| 39 | str = "ElementMode" |
| 40 | case mCodeWithScope: |
| 41 | str = "CodeWithScopeMode" |
| 42 | case mSpacer: |
| 43 | str = "CodeWithScopeSpacerFrame" |
| 44 | default: |
| 45 | str = "UnknownMode" |
| 46 | } |
| 47 | |
| 48 | return str |
| 49 | } |
| 50 | |
| 51 | func (m mode) TypeString() string { |
| 52 | var str string |
| 53 | |
| 54 | switch m { |
| 55 | case mTopLevel: |
| 56 | str = "TopLevel" |
| 57 | case mDocument: |
| 58 | str = "Document" |
| 59 | case mArray: |
| 60 | str = "Array" |
| 61 | case mValue: |
| 62 | str = "Value" |
| 63 | case mElement: |
| 64 | str = "Element" |
| 65 | case mCodeWithScope: |
| 66 | str = "CodeWithScope" |
| 67 | case mSpacer: |
| 68 | str = "CodeWithScopeSpacer" |
| 69 | default: |
| 70 | str = "Unknown" |
| 71 | } |
| 72 | |
| 73 | return str |
| 74 | } |
| 75 | |
| 76 | // TransitionError is an error returned when an invalid progressing a |
| 77 | // ValueReader or ValueWriter state machine occurs. |
| 78 | // If read is false, the error is for writing |
| 79 | type TransitionError struct { |
| 80 | name string |
| 81 | parent mode |
| 82 | current mode |
| 83 | destination mode |
| 84 | modes []mode |
| 85 | action string |
| 86 | } |
| 87 | |
| 88 | func (te TransitionError) Error() string { |
| 89 | errString := fmt.Sprintf("%s can only %s", te.name, te.action) |
| 90 | if te.destination != mode(0) { |
| 91 | errString = fmt.Sprintf("%s a %s", errString, te.destination.TypeString()) |
| 92 | } |
| 93 | errString = fmt.Sprintf("%s while positioned on a", errString) |
| 94 | for ind, m := range te.modes { |
| 95 | if ind != 0 && len(te.modes) > 2 { |
| 96 | errString = fmt.Sprintf("%s,", errString) |
| 97 | } |
| 98 | if ind == len(te.modes)-1 && len(te.modes) > 1 { |
| 99 | errString = fmt.Sprintf("%s or", errString) |
| 100 | } |
| 101 | errString = fmt.Sprintf("%s %s", errString, m.TypeString()) |
| 102 | } |
| 103 | errString = fmt.Sprintf("%s but is positioned on a %s", errString, te.current.TypeString()) |
| 104 | if te.parent != mode(0) { |
| 105 | errString = fmt.Sprintf("%s with parent %s", errString, te.parent.TypeString()) |
| 106 | } |
| 107 | return errString |
| 108 | } |