...

Source file src/github.com/aws/smithy-go/middleware/ordered_group.go

Documentation: github.com/aws/smithy-go/middleware

     1  package middleware
     2  
     3  import "fmt"
     4  
     5  // RelativePosition provides specifying the relative position of a middleware
     6  // in an ordered group.
     7  type RelativePosition int
     8  
     9  // Relative position for middleware in steps.
    10  const (
    11  	After RelativePosition = iota
    12  	Before
    13  )
    14  
    15  type ider interface {
    16  	ID() string
    17  }
    18  
    19  // orderedIDs provides an ordered collection of items with relative ordering
    20  // by name.
    21  type orderedIDs struct {
    22  	order *relativeOrder
    23  	items map[string]ider
    24  }
    25  
    26  const baseOrderedItems = 5
    27  
    28  func newOrderedIDs() *orderedIDs {
    29  	return &orderedIDs{
    30  		order: newRelativeOrder(),
    31  		items: make(map[string]ider, baseOrderedItems),
    32  	}
    33  }
    34  
    35  // Add injects the item to the relative position of the item group. Returns an
    36  // error if the item already exists.
    37  func (g *orderedIDs) Add(m ider, pos RelativePosition) error {
    38  	id := m.ID()
    39  	if len(id) == 0 {
    40  		return fmt.Errorf("empty ID, ID must not be empty")
    41  	}
    42  
    43  	if err := g.order.Add(pos, id); err != nil {
    44  		return err
    45  	}
    46  
    47  	g.items[id] = m
    48  	return nil
    49  }
    50  
    51  // Insert injects the item relative to an existing item id. Returns an error if
    52  // the original item does not exist, or the item being added already exists.
    53  func (g *orderedIDs) Insert(m ider, relativeTo string, pos RelativePosition) error {
    54  	if len(m.ID()) == 0 {
    55  		return fmt.Errorf("insert ID must not be empty")
    56  	}
    57  	if len(relativeTo) == 0 {
    58  		return fmt.Errorf("relative to ID must not be empty")
    59  	}
    60  
    61  	if err := g.order.Insert(relativeTo, pos, m.ID()); err != nil {
    62  		return err
    63  	}
    64  
    65  	g.items[m.ID()] = m
    66  	return nil
    67  }
    68  
    69  // Get returns the ider identified by id. If ider is not present, returns false.
    70  func (g *orderedIDs) Get(id string) (ider, bool) {
    71  	v, ok := g.items[id]
    72  	return v, ok
    73  }
    74  
    75  // Swap removes the item by id, replacing it with the new item. Returns an error
    76  // if the original item doesn't exist.
    77  func (g *orderedIDs) Swap(id string, m ider) (ider, error) {
    78  	if len(id) == 0 {
    79  		return nil, fmt.Errorf("swap from ID must not be empty")
    80  	}
    81  
    82  	iderID := m.ID()
    83  	if len(iderID) == 0 {
    84  		return nil, fmt.Errorf("swap to ID must not be empty")
    85  	}
    86  
    87  	if err := g.order.Swap(id, iderID); err != nil {
    88  		return nil, err
    89  	}
    90  
    91  	removed := g.items[id]
    92  
    93  	delete(g.items, id)
    94  	g.items[iderID] = m
    95  
    96  	return removed, nil
    97  }
    98  
    99  // Remove removes the item by id. Returns an error if the item
   100  // doesn't exist.
   101  func (g *orderedIDs) Remove(id string) (ider, error) {
   102  	if len(id) == 0 {
   103  		return nil, fmt.Errorf("remove ID must not be empty")
   104  	}
   105  
   106  	if err := g.order.Remove(id); err != nil {
   107  		return nil, err
   108  	}
   109  
   110  	removed := g.items[id]
   111  	delete(g.items, id)
   112  	return removed, nil
   113  }
   114  
   115  func (g *orderedIDs) List() []string {
   116  	items := g.order.List()
   117  	order := make([]string, len(items))
   118  	copy(order, items)
   119  	return order
   120  }
   121  
   122  // Clear removes all entries and slots.
   123  func (g *orderedIDs) Clear() {
   124  	g.order.Clear()
   125  	g.items = map[string]ider{}
   126  }
   127  
   128  // GetOrder returns the item in the order it should be invoked in.
   129  func (g *orderedIDs) GetOrder() []interface{} {
   130  	order := g.order.List()
   131  	ordered := make([]interface{}, len(order))
   132  	for i := 0; i < len(order); i++ {
   133  		ordered[i] = g.items[order[i]]
   134  	}
   135  
   136  	return ordered
   137  }
   138  
   139  // relativeOrder provides ordering of item
   140  type relativeOrder struct {
   141  	order []string
   142  }
   143  
   144  func newRelativeOrder() *relativeOrder {
   145  	return &relativeOrder{
   146  		order: make([]string, 0, baseOrderedItems),
   147  	}
   148  }
   149  
   150  // Add inserts an item into the order relative to the position provided.
   151  func (s *relativeOrder) Add(pos RelativePosition, ids ...string) error {
   152  	if len(ids) == 0 {
   153  		return nil
   154  	}
   155  
   156  	for _, id := range ids {
   157  		if _, ok := s.has(id); ok {
   158  			return fmt.Errorf("already exists, %v", id)
   159  		}
   160  	}
   161  
   162  	switch pos {
   163  	case Before:
   164  		return s.insert(0, Before, ids...)
   165  
   166  	case After:
   167  		s.order = append(s.order, ids...)
   168  
   169  	default:
   170  		return fmt.Errorf("invalid position, %v", int(pos))
   171  	}
   172  
   173  	return nil
   174  }
   175  
   176  // Insert injects an item before or after the relative item. Returns
   177  // an error if the relative item does not exist.
   178  func (s *relativeOrder) Insert(relativeTo string, pos RelativePosition, ids ...string) error {
   179  	if len(ids) == 0 {
   180  		return nil
   181  	}
   182  
   183  	for _, id := range ids {
   184  		if _, ok := s.has(id); ok {
   185  			return fmt.Errorf("already exists, %v", id)
   186  		}
   187  	}
   188  
   189  	i, ok := s.has(relativeTo)
   190  	if !ok {
   191  		return fmt.Errorf("not found, %v", relativeTo)
   192  	}
   193  
   194  	return s.insert(i, pos, ids...)
   195  }
   196  
   197  // Swap will replace the item id with the to item. Returns an
   198  // error if the original item id does not exist. Allows swapping out an
   199  // item for another item with the same id.
   200  func (s *relativeOrder) Swap(id, to string) error {
   201  	i, ok := s.has(id)
   202  	if !ok {
   203  		return fmt.Errorf("not found, %v", id)
   204  	}
   205  
   206  	if _, ok = s.has(to); ok && id != to {
   207  		return fmt.Errorf("already exists, %v", to)
   208  	}
   209  
   210  	s.order[i] = to
   211  	return nil
   212  }
   213  
   214  func (s *relativeOrder) Remove(id string) error {
   215  	i, ok := s.has(id)
   216  	if !ok {
   217  		return fmt.Errorf("not found, %v", id)
   218  	}
   219  
   220  	s.order = append(s.order[:i], s.order[i+1:]...)
   221  	return nil
   222  }
   223  
   224  func (s *relativeOrder) List() []string {
   225  	return s.order
   226  }
   227  
   228  func (s *relativeOrder) Clear() {
   229  	s.order = s.order[0:0]
   230  }
   231  
   232  func (s *relativeOrder) insert(i int, pos RelativePosition, ids ...string) error {
   233  	switch pos {
   234  	case Before:
   235  		n := len(ids)
   236  		var src []string
   237  		if n <= cap(s.order)-len(s.order) {
   238  			s.order = s.order[:len(s.order)+n]
   239  			src = s.order
   240  		} else {
   241  			src = s.order
   242  			s.order = make([]string, len(s.order)+n)
   243  			copy(s.order[:i], src[:i]) // only when allocating a new slice do we need to copy the front half
   244  		}
   245  		copy(s.order[i+n:], src[i:])
   246  		copy(s.order[i:], ids)
   247  	case After:
   248  		if i == len(s.order)-1 || len(s.order) == 0 {
   249  			s.order = append(s.order, ids...)
   250  		} else {
   251  			s.order = append(s.order[:i+1], append(ids, s.order[i+1:]...)...)
   252  		}
   253  
   254  	default:
   255  		return fmt.Errorf("invalid position, %v", int(pos))
   256  	}
   257  
   258  	return nil
   259  }
   260  
   261  func (s *relativeOrder) has(id string) (i int, found bool) {
   262  	for i := 0; i < len(s.order); i++ {
   263  		if s.order[i] == id {
   264  			return i, true
   265  		}
   266  	}
   267  	return 0, false
   268  }
   269  

View as plain text