From 8344699a0d8ce94584251e5573bdf14736cb13a8 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 22 May 2024 16:55:41 -0700 Subject: [PATCH] lntypes: Add Dual[A] primitive type This commit introduces a new type Dual[A] to make it easier to manage symmetric configurations or state for lightning channels. --- lntypes/channel_party.go | 67 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/lntypes/channel_party.go b/lntypes/channel_party.go index be800541b..5848becee 100644 --- a/lntypes/channel_party.go +++ b/lntypes/channel_party.go @@ -50,3 +50,70 @@ func (p ChannelParty) IsLocal() bool { func (p ChannelParty) IsRemote() bool { return p == Remote } + +// Dual represents a structure when we are tracking the same parameter for both +// the Local and Remote parties. +type Dual[A any] struct { + // Local is the value tracked for the Local ChannelParty. + Local A + + // Remote is the value tracked for the Remote ChannelParty. + Remote A +} + +// GetForParty gives Dual an access method that takes a ChannelParty as an +// argument. It is included for ergonomics in cases where the ChannelParty is +// in a variable and which party determines how we want to access the Dual. +func (d *Dual[A]) GetForParty(p ChannelParty) A { + switch p { + case Local: + return d.Local + case Remote: + return d.Remote + default: + panic(fmt.Sprintf( + "switch default triggered in ForParty: %v", p, + )) + } +} + +// SetForParty sets the value in the Dual for the given ChannelParty. This +// returns a copy of the original value. +func (d *Dual[A]) SetForParty(p ChannelParty, value A) { + switch p { + case Local: + d.Local = value + case Remote: + d.Remote = value + default: + panic(fmt.Sprintf( + "switch default triggered in ForParty: %v", p, + )) + } +} + +// ModifyForParty applies the function argument to the given ChannelParty field +// and returns a new copy of the Dual. +func (d *Dual[A]) ModifyForParty(p ChannelParty, f func(A) A) A { + switch p { + case Local: + d.Local = f(d.Local) + return d.Local + case Remote: + d.Remote = f(d.Remote) + return d.Remote + default: + panic(fmt.Sprintf( + "switch default triggered in ForParty: %v", p, + )) + } +} + +// MapDual applies the function argument to both the Local and Remote fields of +// the Dual[A] and returns a Dual[B] with that function applied. +func MapDual[A, B any](d Dual[A], f func(A) B) Dual[B] { + return Dual[B]{ + Local: f(d.Local), + Remote: f(d.Remote), + } +}