package branchmanager import ( "github.com/iotaledger/hive.go/marshalutil" "github.com/iotaledger/hive.go/objectstorage" ) // ConflictMember represents the relationship between a Conflict and its Branches. Since a Conflict can have a // potentially unbounded amount of conflicting Consumers, we store this as a separate k/v pair instead of a marshaled // ist of members inside the Branch. type ConflictMember struct { objectstorage.StorableObjectFlags conflictID ConflictID branchID BranchID } // NewConflictMember is the constructor of the ConflictMember reference. func NewConflictMember(conflictID ConflictID, branchID BranchID) *ConflictMember { return &ConflictMember{ conflictID: conflictID, branchID: branchID, } } // ConflictMemberFromBytes unmarshals a ConflictMember from a sequence of bytes. func ConflictMemberFromBytes(bytes []byte, optionalTargetObject ...*ConflictMember) (result *ConflictMember, consumedBytes int, err error) { marshalUtil := marshalutil.New(bytes) result, err = ParseConflictMember(marshalUtil, optionalTargetObject...) consumedBytes = marshalUtil.ReadOffset() return } // ConflictMemberFromStorageKey is a factory method that creates a new ConflictMember instance from a storage key of the // objectstorage. It is used by the objectstorage, to create new instances of this entity. func ConflictMemberFromStorageKey(key []byte, optionalTargetObject ...*ConflictMember) (result *ConflictMember, consumedBytes int, err error) { // determine the target object that will hold the unmarshaled information switch len(optionalTargetObject) { case 0: result = &ConflictMember{} case 1: result = optionalTargetObject[0] default: panic("too many arguments in call to ConflictMemberFromStorageKey") } // parse the properties that are stored in the key marshalUtil := marshalutil.New(key) if result.conflictID, err = ParseConflictID(marshalUtil); err != nil { return } if result.branchID, err = ParseBranchID(marshalUtil); err != nil { return } consumedBytes = marshalUtil.ReadOffset() return } // ParseConflictMember unmarshals a ConflictMember using the given marshalUtil (for easier marshaling/unmarshaling). func ParseConflictMember(marshalUtil *marshalutil.MarshalUtil, optionalTargetObject ...*ConflictMember) (result *ConflictMember, err error) { parsedObject, parseErr := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return ConflictMemberFromStorageKey(data, optionalTargetObject...) }) if parseErr != nil { err = parseErr return } result = parsedObject.(*ConflictMember) _, err = marshalUtil.Parse(func(data []byte) (parseResult interface{}, parsedBytes int, parseErr error) { parsedBytes, parseErr = result.UnmarshalObjectStorageValue(data) return }) return } // ConflictID returns the identifier of the Conflict that this conflictMember belongs to. func (conflictMember *ConflictMember) ConflictID() ConflictID { return conflictMember.conflictID } // BranchID returns the identifier of the Branch that this conflictMember references. func (conflictMember *ConflictMember) BranchID() BranchID { return conflictMember.branchID } // ObjectStorageKey returns the bytes that are used a key when storing the Branch in an objectstorage. func (conflictMember ConflictMember) ObjectStorageKey() []byte { return marshalutil.New(ConflictIDLength + BranchIDLength). WriteBytes(conflictMember.conflictID.Bytes()). WriteBytes(conflictMember.branchID.Bytes()). Bytes() } // ObjectStorageValue returns the bytes that represent all remaining information (not stored in the key) of a marshaled // ConflictMember. func (conflictMember ConflictMember) ObjectStorageValue() []byte { return nil } // UnmarshalObjectStorageValue returns the bytes that represent all remaining information (not stored in the key) of a // marshaled Branch. func (conflictMember ConflictMember) UnmarshalObjectStorageValue([]byte) (consumedBytes int, err error) { return } // Update is disabled but needs to be implemented to be compatible with the objectstorage. func (conflictMember ConflictMember) Update(other objectstorage.StorableObject) { panic("updates are disabled - use the setters") } var _ objectstorage.StorableObject = &ConflictMember{} // CachedConflictMember is a wrapper for the generic CachedObject returned by the objectstorage that overrides the // accessor methods, with a type-casted one. type CachedConflictMember struct { objectstorage.CachedObject } // Retain marks this CachedObject to still be in use by the program. func (cachedConflictMember *CachedConflictMember) Retain() *CachedConflictMember { return &CachedConflictMember{cachedConflictMember.CachedObject.Retain()} } // Unwrap is the type-casted equivalent of Get. It returns nil if the object does not exist. func (cachedConflictMember *CachedConflictMember) Unwrap() *ConflictMember { untypedObject := cachedConflictMember.Get() if untypedObject == nil { return nil } typedObject := untypedObject.(*ConflictMember) if typedObject == nil || typedObject.IsDeleted() { return nil } return typedObject } // Consume unwraps the CachedObject and passes a type-casted version to the consumer (if the object is not empty - it // exists). It automatically releases the object when the consumer finishes. func (cachedConflictMember *CachedConflictMember) Consume(consumer func(conflictMember *ConflictMember), forceRelease ...bool) (consumed bool) { return cachedConflictMember.CachedObject.Consume(func(object objectstorage.StorableObject) { consumer(object.(*ConflictMember)) }, forceRelease...) } // CachedConflictMembers represents a collection of CachedConflictMembers. type CachedConflictMembers []*CachedConflictMember // Consume iterates over the CachedObjects, unwraps them and passes a type-casted version to the consumer (if the object // is not empty - it exists). It automatically releases the object when the consumer finishes. It returns true, if at // least one object was consumed. func (cachedConflictMembers CachedConflictMembers) Consume(consumer func(conflictMember *ConflictMember)) (consumed bool) { for _, cachedConflictMember := range cachedConflictMembers { consumed = cachedConflictMember.Consume(func(output *ConflictMember) { consumer(output) }) || consumed } return } // Release is a utility function that allows us to release all CachedObjects in the collection. func (cachedConflictMembers CachedConflictMembers) Release(force ...bool) { for _, cachedConflictMember := range cachedConflictMembers { cachedConflictMember.Release(force...) } }