2025-03-26 18:49:42 -06:00

353 lines
7.1 KiB
Go

package twt_pb
import (
"io"
"iter"
"slices"
"time"
"go.yarn.social/lextwt"
"go.yarn.social/types"
"google.golang.org/protobuf/proto"
)
type twtRegistry interface {
Twters() []*types.Twter
Preamble() lextwt.Comments
Twts() types.Twts
WriteTo(w io.Writer) (int64, error)
}
func EncodeRegistry(r twtRegistry) ([]byte, error) {
o := &TwtRegistry{}
o.FromLextwt(r)
return proto.Marshal(o)
}
func DecodeRegistry(b []byte) (twtRegistry, error) {
o := &TwtRegistry{}
err := proto.Unmarshal(b, o)
if err != nil {
return nil, err
}
return o.ToLextwt(), nil
}
func (r *TwtRegistry) FromLextwt(twt twtRegistry) error {
preamble := twt.Preamble()
r.Preamble = apply(
slices.All(preamble),
make([]*Comment, len(preamble)),
fromComment)
twts := twt.Twts()
r.Twts = apply(
slices.All(twts),
make([]*Twt, len(twts)),
fromTwt)
return nil
}
func (r *TwtRegistry) ToLextwt() twtRegistry {
return lextwt.NewTwtRegistry(
apply(slices.All(r.Preamble), make(lextwt.Comments, len(r.Preamble)), func(c *Comment) *lextwt.Comment {
return c.ToLextwt()
}),
apply(slices.All(r.Twts), make(types.Twts, len(r.Twts)), func(c *Twt) types.Twt {
return c.ToLextwt()
}),
)
}
type twtFeed interface {
Twter() *types.Twter
Preamble() lextwt.Comments
Twts() types.Twts
WriteTo(w io.Writer) (int64, error)
}
func EncodeFeed(r twtFeed) ([]byte, error) {
o := &TwtFeed{}
o.FromLextwt(r)
return proto.Marshal(o)
}
func DecodeFeed(b []byte) (twtFeed, error) {
o := &TwtFeed{}
err := proto.Unmarshal(b, o)
if err != nil {
return nil, err
}
return o.ToLextwt(), nil
}
func (r *TwtFeed) FromLextwt(twt twtFeed) error {
r.Twter = fromTwter(twt.Twter())
preamble := twt.Preamble()
r.Preamble = apply(
slices.All(preamble),
make([]*Comment, len(preamble)),
fromComment)
twts := twt.Twts()
r.Twts = apply(
slices.All(twts),
make([]*Twt, len(twts)),
fromTwt)
return nil
}
func (r *TwtFeed) ToLextwt() twtFeed {
return lextwt.NewTwtFile(
*r.Twter.ToLextwt(),
apply(slices.All(r.Preamble), make(lextwt.Comments, len(r.Preamble)), func(c *Comment) *lextwt.Comment {
return c.ToLextwt()
}),
apply(slices.All(r.Twts), make(types.Twts, len(r.Twts)), func(c *Twt) types.Twt {
return c.ToLextwt()
}),
)
}
func apply[U, V any](u iter.Seq2[int, U], v []V, fn func(U) V) []V {
for i, u := range u {
v[i] = fn(u)
}
return v
}
func (e *Twter) FromLextwt(twt *types.Twter) {
e.Nick = twt.Nick
e.Uri = twt.URI
}
func fromTwter(twt *types.Twter) *Twter {
return &Twter{
Nick: twt.Nick,
Uri: twt.URI,
}
}
func (e *Twter) ToLextwt() *types.Twter {
return &types.Twter{
Nick: e.Nick,
URI: e.Uri,
}
}
func (e *Twt) FromLextwt(twt *lextwt.Twt) {
twter := twt.Twter()
e.Twter.FromLextwt(&twter)
e.Created = fromDateTime(twt.Created())
e.Msg = apply(
slices.All(twt.Elems()),
make([]*Elem, len(twt.Elems())),
fromElem,
)
}
func fromTwt(twt types.Twt) *Twt {
twter := twt.Twter()
lx, ok := twt.(*lextwt.Twt)
if !ok {
return &Twt{}
}
msg := lx.Elems()
return &Twt{
Twter: fromTwter(&twter),
Created: fromDateTime(twt.Created()),
Msg: apply(
slices.All(msg),
make([]*Elem, len(msg)),
fromElem,
),
}
}
func (e *Twt) ToLextwt() *lextwt.Twt {
return lextwt.NewTwt(
*e.Twter.ToLextwt(),
e.Created.ToLextwt(),
apply(
slices.All(e.Msg),
make([]lextwt.Elem, len(e.Msg)),
func(e *Elem) lextwt.Elem {
return e.ToLextwt()
},
)...,
)
}
func fromDateTime(t time.Time) *DateTime {
zone, offset := t.Zone()
return &DateTime{
Timestamp: t.UnixMicro(),
Offset: int32(offset),
Zone: zone,
}
}
func (c *DateTime) ToLextwt() *lextwt.DateTime {
dt := time.UnixMicro(c.Timestamp)
dt = dt.In(time.FixedZone(c.Zone, int(c.Offset)))
return lextwt.NewDateTime(dt, dt.Format(time.RFC3339))
}
func fromElem(e lextwt.Elem) *Elem {
if e == lextwt.LineSeparator {
return &Elem{Elem: &Elem_Lineseparator{fromLineSeparator()}}
}
switch e := e.(type) {
case *lextwt.BangMention:
return &Elem{Elem: &Elem_Bangmention{fromBangMention(e)}}
case *lextwt.Code:
return &Elem{Elem: &Elem_Code{fromCode(e)}}
case *lextwt.Comment:
return &Elem{Elem: &Elem_Comment{fromComment(e)}}
case *lextwt.Mention:
return &Elem{Elem: &Elem_Mention{fromMention(e)}}
case *lextwt.Subject:
return &Elem{Elem: &Elem_Subject{fromSubject(e)}}
case *lextwt.Tag:
return &Elem{Elem: &Elem_Tag{fromTag(e)}}
case *lextwt.Link:
return &Elem{Elem: &Elem_Link{fromLink(e)}}
case *lextwt.Text:
return &Elem{Elem: &Elem_Text{fromText(e)}}
}
return &Elem{}
}
func (c *Elem) ToLextwt() lextwt.Elem {
switch e := c.Elem.(type) {
case *Elem_Bangmention:
return e.Bangmention.ToLextwt()
case *Elem_Code:
return e.Code.ToLextwt()
case *Elem_Comment:
return e.Comment.ToLextwt()
case *Elem_Lineseparator:
return e.Lineseparator.ToLextwt()
case *Elem_Link:
return e.Link.ToLextwt()
case *Elem_Mention:
return e.Mention.ToLextwt()
case *Elem_Subject:
return e.Subject.ToLextwt()
case *Elem_Tag:
return e.Tag.ToLextwt()
case *Elem_Text:
return e.Text.ToLextwt()
}
return nil
}
func fromCode(c *lextwt.Code) *Code {
return &Code{
Type: Code_Type(c.CodeType()),
Code: c.Text(),
}
}
func (c *Code) ToLextwt() *lextwt.Code {
return lextwt.NewCode(c.Code, lextwt.CodeType(c.Type))
}
func fromComment(c *lextwt.Comment) *Comment {
return &Comment{
Comment: c.Text(),
Key: c.Key(),
Value: c.Value(),
}
}
func (c *Comment) ToLextwt() *lextwt.Comment {
if c.Key != "" {
return lextwt.NewCommentValue(c.Comment, c.Key, c.Value)
}
return lextwt.NewComment(c.Comment)
}
func fromBangMention(c *lextwt.BangMention) *BangMention {
return &BangMention{
Name: c.Name(),
Target: c.Target(),
}
}
func (c *BangMention) ToLextwt() *lextwt.BangMention {
return lextwt.NewBangMention(c.Name, c.Target)
}
func fromMention(c *lextwt.Mention) *Mention {
return &Mention{
Name: c.Name(),
Target: c.Target(),
}
}
func (c *Mention) ToLextwt() *lextwt.Mention {
return lextwt.NewMention(c.Name, c.Target)
}
func fromTag(c *lextwt.Tag) *Tag {
return &Tag{
Tag: c.Text(),
Target: c.Target(),
}
}
func (c *Tag) ToLextwt() *lextwt.Tag {
return lextwt.NewTag(c.Tag, c.Target)
}
func fromLineSeparator() *LineSeparator {
return &LineSeparator{}
}
func (c *LineSeparator) ToLextwt() lextwt.Elem {
return lextwt.LineSeparator
}
func fromLink(c *lextwt.Link) *Link {
return &Link{
Type: Link_Type(c.LinkType()),
Alt: c.Text(),
Target: c.Target(),
Title: c.Title(),
}
}
func (c *Link) ToLextwt() *lextwt.Link {
if c.Type == Link_Type(lextwt.LinkMedia) {
return lextwt.NewMedia(c.Alt, c.Target, c.Title)
}
return lextwt.NewLink(c.Alt, c.Target, lextwt.LinkType(c.Type))
}
func fromSubject(c *lextwt.Subject) *Subject {
if tag, ok := c.Tag().(*lextwt.Tag); ok {
return &Subject{
Tag: fromTag(tag),
}
}
return &Subject{
Subject: c.Text(),
}
}
func (c *Subject) ToLextwt() *lextwt.Subject {
if c.Tag != nil {
return lextwt.NewSubjectTag(c.Tag.Tag, c.Tag.Target)
}
return lextwt.NewSubject(c.Subject)
}
func fromText(c *lextwt.Text) *Text {
return &Text{
Text: c.Literal(),
}
}
func (c *Text) ToLextwt() *lextwt.Text {
return lextwt.NewText(c.Text)
}