github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/commons/versions/interval.go (about)

     1  /*
     2   * Copyright 2023 Wang Min Xiang
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   * 	http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   */
    17  
    18  package versions
    19  
    20  import (
    21  	"bytes"
    22  	"fmt"
    23  	"github.com/aacfactory/errors"
    24  	"github.com/aacfactory/fns/commons/bytex"
    25  	"github.com/valyala/bytebufferpool"
    26  )
    27  
    28  type Interval []Version
    29  
    30  func (interval Interval) Accept(target Version) (ok bool) {
    31  	n := len(interval)
    32  	if n == 0 { // [v0.0.0, latest)
    33  		ok = true
    34  		return
    35  	}
    36  	if n == 1 { // [{left}, latest)
    37  		ok = target.Between(interval[0], Latest())
    38  		return
    39  	}
    40  	// [{left}, {right}})
    41  	ok = target.Between(interval[0], interval[1])
    42  	return
    43  }
    44  
    45  func (interval Interval) String() string {
    46  	n := len(interval)
    47  	if n == 0 {
    48  		return "[v0.0.0, latest)"
    49  	}
    50  	if n == 1 {
    51  		return fmt.Sprintf("[%s, latest)", interval[0].String())
    52  	}
    53  	return fmt.Sprintf("[%s, %s)", interval[0].String(), interval[1].String())
    54  }
    55  
    56  // ParseInterval
    57  // left:right
    58  func ParseInterval(source []byte) (interval Interval, err error) {
    59  	ss := bytes.Split(source, []byte{':'})
    60  	n := len(ss)
    61  	if n == 0 {
    62  		interval = Interval{Origin(), Latest()}
    63  		return
    64  	}
    65  	if n == 1 {
    66  		ver, parseErr := Parse(ss[0])
    67  		if parseErr != nil {
    68  			err = errors.Warning("fns: parse interval failed").WithMeta("source", bytex.ToString(source)).WithCause(parseErr)
    69  			return
    70  		}
    71  		interval = Interval{ver, Latest()}
    72  		return
    73  	}
    74  	if n == 2 {
    75  		left, leftErr := Parse(ss[0])
    76  		if leftErr != nil {
    77  			err = errors.Warning("fns: parse interval failed").WithMeta("source", bytex.ToString(source)).WithCause(leftErr)
    78  			return
    79  		}
    80  		right, rightErr := Parse(ss[1])
    81  		if rightErr != nil {
    82  			err = errors.Warning("fns: parse interval failed").WithMeta("source", bytex.ToString(source)).WithCause(rightErr)
    83  			return
    84  		}
    85  		if right.LessThan(left) {
    86  			err = errors.Warning("fns: parse interval failed").WithMeta("source", bytex.ToString(source)).WithCause(fmt.Errorf("invalid interval"))
    87  			return
    88  		}
    89  		interval = Interval{left, right}
    90  		return
    91  	}
    92  	err = errors.Warning("fns: parse interval failed").WithMeta("source", bytex.ToString(source)).WithCause(fmt.Errorf("invalid interval"))
    93  	return
    94  }
    95  
    96  type NamedInterval struct {
    97  	Name  []byte   `json:"name"`
    98  	Value Interval `json:"value"`
    99  }
   100  
   101  type Intervals []NamedInterval
   102  
   103  func (intervals Intervals) Accept(name []byte, target Version) (ok bool) {
   104  	if len(intervals) == 0 {
   105  		ok = true
   106  		return
   107  	}
   108  	for _, interval := range intervals {
   109  		if bytes.Equal(name, interval.Name) {
   110  			ok = interval.Value.Accept(target)
   111  			break
   112  		}
   113  	}
   114  	return
   115  }
   116  
   117  func (intervals Intervals) Get(name []byte) (interval Interval, has bool) {
   118  	if len(intervals) == 0 {
   119  		return
   120  	}
   121  	for _, namedInterval := range intervals {
   122  		if bytes.Equal(name, namedInterval.Name) {
   123  			interval = namedInterval.Value
   124  			has = true
   125  			return
   126  		}
   127  	}
   128  	return
   129  }
   130  
   131  func (intervals Intervals) Bytes() []byte {
   132  	if len(intervals) == 0 {
   133  		return []byte{}
   134  	}
   135  	p := bytebufferpool.Get()
   136  	defer bytebufferpool.Put(p)
   137  	for _, interval := range intervals {
   138  		_, _ = p.Write([]byte{',', ' '})
   139  		_, _ = p.Write(interval.Name)
   140  		_, _ = p.Write([]byte{'='})
   141  		_, _ = p.Write(bytex.FromString(interval.Value.String()))
   142  	}
   143  	return p.Bytes()[2:]
   144  }
   145  
   146  func (intervals Intervals) String() string {
   147  	return bytex.ToString(intervals.Bytes())
   148  }
   149  
   150  // ParseIntervals
   151  // key=left:right, ...
   152  func ParseIntervals(source []byte) (intervals Intervals, err error) {
   153  	if len(source) == 0 {
   154  		return
   155  	}
   156  	ss := bytes.Split(source, []byte{','})
   157  	for _, s := range ss {
   158  		s = bytes.TrimSpace(s)
   159  		idx := bytes.IndexByte(s, '=')
   160  		if idx < 1 {
   161  			err = errors.Warning("fns: parse intervals failed").WithMeta("source", bytex.ToString(source)).WithCause(fmt.Errorf("invalid intervals"))
   162  			return
   163  		}
   164  		name := bytes.TrimSpace(s[0:idx])
   165  		interval, parseErr := ParseInterval(s[idx+1:])
   166  		if parseErr != nil {
   167  			err = errors.Warning("fns: parse intervals failed").WithMeta("source", bytex.ToString(source)).WithCause(parseErr)
   168  			return
   169  		}
   170  		if intervals == nil {
   171  			intervals = make(Intervals, 0, 1)
   172  		}
   173  		intervals = append(intervals, NamedInterval{
   174  			Name:  name,
   175  			Value: interval,
   176  		})
   177  	}
   178  	return
   179  }