mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-23 04:06:39 +00:00
204 lines
4.9 KiB
Go
204 lines
4.9 KiB
Go
/*
|
|
* Copyright 2021 ByteDance Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package ast
|
|
|
|
import (
|
|
`fmt`
|
|
|
|
`github.com/bytedance/sonic/internal/native/types`
|
|
)
|
|
|
|
type Pair struct {
|
|
Key string
|
|
Value Node
|
|
}
|
|
|
|
// Values returns iterator for array's children traversal
|
|
func (self *Node) Values() (ListIterator, error) {
|
|
if err := self.should(types.V_ARRAY, "an array"); err != nil {
|
|
return ListIterator{}, err
|
|
}
|
|
return self.values(), nil
|
|
}
|
|
|
|
func (self *Node) values() ListIterator {
|
|
return ListIterator{Iterator{p: self}}
|
|
}
|
|
|
|
// Properties returns iterator for object's children traversal
|
|
func (self *Node) Properties() (ObjectIterator, error) {
|
|
if err := self.should(types.V_OBJECT, "an object"); err != nil {
|
|
return ObjectIterator{}, err
|
|
}
|
|
return self.properties(), nil
|
|
}
|
|
|
|
func (self *Node) properties() ObjectIterator {
|
|
return ObjectIterator{Iterator{p: self}}
|
|
}
|
|
|
|
type Iterator struct {
|
|
i int
|
|
p *Node
|
|
}
|
|
|
|
func (self *Iterator) Pos() int {
|
|
return self.i
|
|
}
|
|
|
|
func (self *Iterator) Len() int {
|
|
return self.p.len()
|
|
}
|
|
|
|
// HasNext reports if it is the end of iteration or has error.
|
|
func (self *Iterator) HasNext() bool {
|
|
if !self.p.isLazy() {
|
|
return self.p.Valid() && self.i < self.p.len()
|
|
} else if self.p.t == _V_ARRAY_LAZY {
|
|
return self.p.skipNextNode().Valid()
|
|
} else if self.p.t == _V_OBJECT_LAZY {
|
|
pair := self.p.skipNextPair()
|
|
if pair == nil {
|
|
return false
|
|
}
|
|
return pair.Value.Valid()
|
|
}
|
|
return false
|
|
}
|
|
|
|
// ListIterator is specialized iterator for V_ARRAY
|
|
type ListIterator struct {
|
|
Iterator
|
|
}
|
|
|
|
// ObjectIterator is specialized iterator for V_ARRAY
|
|
type ObjectIterator struct {
|
|
Iterator
|
|
}
|
|
|
|
func (self *ListIterator) next() *Node {
|
|
next_start:
|
|
if !self.HasNext() {
|
|
return nil
|
|
} else {
|
|
n := self.p.nodeAt(self.i)
|
|
self.i++
|
|
if !n.Exists() {
|
|
goto next_start
|
|
}
|
|
return n
|
|
}
|
|
}
|
|
|
|
// Next scans through children of underlying V_ARRAY,
|
|
// copies each child to v, and returns .HasNext().
|
|
func (self *ListIterator) Next(v *Node) bool {
|
|
n := self.next()
|
|
if n == nil {
|
|
return false
|
|
}
|
|
*v = *n
|
|
return true
|
|
}
|
|
|
|
func (self *ObjectIterator) next() *Pair {
|
|
next_start:
|
|
if !self.HasNext() {
|
|
return nil
|
|
} else {
|
|
n := self.p.pairAt(self.i)
|
|
self.i++
|
|
if n == nil || !n.Value.Exists() {
|
|
goto next_start
|
|
}
|
|
return n
|
|
}
|
|
}
|
|
|
|
// Next scans through children of underlying V_OBJECT,
|
|
// copies each child to v, and returns .HasNext().
|
|
func (self *ObjectIterator) Next(p *Pair) bool {
|
|
n := self.next()
|
|
if n == nil {
|
|
return false
|
|
}
|
|
*p = *n
|
|
return true
|
|
}
|
|
|
|
// Sequence represents scanning path of single-layer nodes.
|
|
// Index indicates the value's order in both V_ARRAY and V_OBJECT json.
|
|
// Key is the value's key (for V_OBJECT json only, otherwise it will be nil).
|
|
type Sequence struct {
|
|
Index int
|
|
Key *string
|
|
// Level int
|
|
}
|
|
|
|
// String is string representation of one Sequence
|
|
func (s Sequence) String() string {
|
|
k := ""
|
|
if s.Key != nil {
|
|
k = *s.Key
|
|
}
|
|
return fmt.Sprintf("Sequence(%d, %q)", s.Index, k)
|
|
}
|
|
|
|
type Scanner func(path Sequence, node *Node) bool
|
|
|
|
// ForEach scans one V_OBJECT node's children from JSON head to tail,
|
|
// and pass the Sequence and Node of corresponding JSON value.
|
|
//
|
|
// Especailly, if the node is not V_ARRAY or V_OBJECT,
|
|
// the node itself will be returned and Sequence.Index == -1.
|
|
//
|
|
// NOTICE: A unsetted node WON'T trigger sc, but its index still counts into Path.Index
|
|
func (self *Node) ForEach(sc Scanner) error {
|
|
switch self.itype() {
|
|
case types.V_ARRAY:
|
|
iter, err := self.Values()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
v := iter.next()
|
|
for v != nil {
|
|
if !sc(Sequence{iter.i-1, nil}, v) {
|
|
return nil
|
|
}
|
|
v = iter.next()
|
|
}
|
|
case types.V_OBJECT:
|
|
iter, err := self.Properties()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
v := iter.next()
|
|
for v != nil {
|
|
if !sc(Sequence{iter.i-1, &v.Key}, &v.Value) {
|
|
return nil
|
|
}
|
|
v = iter.next()
|
|
}
|
|
default:
|
|
if self.Check() != nil {
|
|
return self
|
|
}
|
|
sc(Sequence{-1, nil}, self)
|
|
}
|
|
return nil
|
|
}
|