This repository has been archived on 2022-11-27. You can view files and clone it, but cannot push or open issues or pull requests.
activitypub/item_collection.go

229 lines
4.6 KiB
Go

package activitypub
import (
"reflect"
"sort"
)
// ItemCollection represents an array of items
type ItemCollection []Item
// GetID returns the ID corresponding to ItemCollection
func (i ItemCollection) GetID() ID {
return EmptyID
}
// GetLink returns the empty IRI
func (i ItemCollection) GetLink() IRI {
return EmptyIRI
}
// GetType returns the ItemCollection's type
func (i ItemCollection) GetType() ActivityVocabularyType {
return CollectionOfItems
}
// IsLink returns false for an ItemCollection object
func (i ItemCollection) IsLink() bool {
return false
}
// IsObject returns true for a ItemCollection object
func (i ItemCollection) IsObject() bool {
return false
}
// MarshalJSON encodes the receiver object to a JSON document.
func (i ItemCollection) MarshalJSON() ([]byte, error) {
if i == nil {
return nil, nil
}
b := make([]byte, 0)
JSONWriteItemCollectionJSONValue(&b, i)
return b, nil
}
// Append facilitates adding elements to Item arrays
// and ensures ItemCollection implements the Collection interface
func (i *ItemCollection) Append(o Item) error {
*i = append(*i, o)
return nil
}
// Count returns the length of Items in the item collection
func (i *ItemCollection) Count() uint {
if i == nil {
return 0
}
return uint(len(*i))
}
// First returns the ID corresponding to ItemCollection
func (i ItemCollection) First() Item {
if len(i) == 0 {
return nil
}
return i[0]
}
// Normalize returns the first item if the collection contains only one,
// the full collection if the collection contains more than one item,
// or nil
func (i ItemCollection) Normalize() Item {
if len(i) == 0 {
return nil
}
if len(i) == 1 {
return i[0]
}
return i
}
// Collection returns the current object as collection interface
func (i *ItemCollection) Collection() ItemCollection {
return *i
}
// IsCollection returns true for ItemCollection arrays
func (i ItemCollection) IsCollection() bool {
return true
}
// Contains verifies if IRIs array contains the received one
func (i ItemCollection) Contains(r Item) bool {
if len(i) == 0 {
return false
}
for _, it := range i {
if ItemsEqual(it, r) {
return true
}
}
return false
}
// Remove removes the r Item from the i ItemCollection if it contains it
func (i *ItemCollection) Remove(r Item) {
li := len(*i)
if li == 0 {
return
}
if r == nil {
return
}
remIdx := -1
for idx, it := range *i {
if ItemsEqual(it, r) {
remIdx = idx
}
}
if remIdx == -1 {
return
}
if remIdx < li-1 {
*i = append((*i)[:remIdx], (*i)[remIdx+1:]...)
} else {
*i = (*i)[:remIdx]
}
}
// ItemCollectionDeduplication normalizes the received arguments lists into a single unified one
func ItemCollectionDeduplication(recCols ...*ItemCollection) ItemCollection {
rec := make(ItemCollection, 0)
for _, recCol := range recCols {
if recCol == nil {
continue
}
toRemove := make([]int, 0)
for i, cur := range *recCol {
save := true
if cur == nil {
continue
}
var testIt IRI
if cur.IsObject() {
testIt = cur.GetID()
} else if cur.IsLink() {
testIt = cur.GetLink()
} else {
continue
}
for _, it := range rec {
if testIt.Equals(it.GetID(), false) {
// mark the element for removal
toRemove = append(toRemove, i)
save = false
}
}
if save {
rec = append(rec, testIt)
}
}
sort.Sort(sort.Reverse(sort.IntSlice(toRemove)))
for _, idx := range toRemove {
*recCol = append((*recCol)[:idx], (*recCol)[idx+1:]...)
}
}
return rec
}
// ToItemCollection
func ToItemCollection(it Item) (*ItemCollection, error) {
switch i := it.(type) {
case *ItemCollection:
return i, nil
case ItemCollection:
return &i, nil
default:
// NOTE(marius): this is an ugly way of dealing with the interface conversion error: types from different scopes
typ := reflect.TypeOf(new(ItemCollection))
if reflect.TypeOf(it).ConvertibleTo(typ) {
if i, ok := reflect.ValueOf(it).Convert(typ).Interface().(*ItemCollection); ok {
return i, nil
}
}
}
return nil, ErrorInvalidType[ItemCollection](it)
}
// ItemsMatch
func (i ItemCollection) ItemsMatch(col ...Item) bool {
for _, it := range col {
if match := i.Contains(it); !match {
return false
}
}
return true
}
// Equals
func (i ItemCollection) Equals(with Item) bool {
if IsNil(with) {
return false
}
if !with.IsCollection() {
return false
}
if with.GetType() != CollectionOfItems {
return false
}
result := true
OnItemCollection(with, func(w *ItemCollection) error {
if w.Count() != i.Count() {
result = false
return nil
}
for _, it := range i {
if !w.Contains(it.GetLink()) {
result = false
return nil
}
}
return nil
})
return result
}