211 lines
4.3 KiB
Go
211 lines
4.3 KiB
Go
// Licensed to Elasticsearch B.V. under one or more contributor
|
|
// license agreements. See the NOTICE file distributed with
|
|
// this work for additional information regarding copyright
|
|
// ownership. Elasticsearch B.V. licenses this file to you 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 dtfmt
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
type element interface {
|
|
requires(c *ctxConfig) error
|
|
estimateSize() int
|
|
compile() (prog, error)
|
|
}
|
|
|
|
type runeLiteral struct {
|
|
r rune
|
|
}
|
|
|
|
type stringLiteral struct {
|
|
s []byte
|
|
}
|
|
|
|
type unpaddedNumber struct {
|
|
ft fieldType
|
|
maxDigits int
|
|
signed bool
|
|
}
|
|
|
|
type paddedNumber struct {
|
|
ft fieldType
|
|
div int
|
|
minDigits, maxDigits int
|
|
signed bool
|
|
}
|
|
|
|
type textField struct {
|
|
ft fieldType
|
|
short bool
|
|
}
|
|
|
|
type twoDigitYear struct {
|
|
ft fieldType
|
|
}
|
|
|
|
type paddingZeros struct {
|
|
count int
|
|
}
|
|
|
|
func (runeLiteral) requires(*ctxConfig) error { return nil }
|
|
func (runeLiteral) estimateSize() int { return 1 }
|
|
|
|
func (stringLiteral) requires(*ctxConfig) error { return nil }
|
|
func (s stringLiteral) estimateSize() int { return len(s.s) }
|
|
|
|
func (n unpaddedNumber) requires(c *ctxConfig) error {
|
|
return numRequires(c, n.ft)
|
|
}
|
|
|
|
func (n unpaddedNumber) estimateSize() int {
|
|
return numSize(n.maxDigits, n.signed)
|
|
}
|
|
|
|
func (n paddedNumber) requires(c *ctxConfig) error {
|
|
return numRequires(c, n.ft)
|
|
}
|
|
|
|
func (n paddedNumber) estimateSize() int {
|
|
return numSize(n.maxDigits, n.signed)
|
|
}
|
|
|
|
func (n twoDigitYear) requires(c *ctxConfig) error {
|
|
return numRequires(c, n.ft)
|
|
}
|
|
|
|
func (twoDigitYear) estimateSize() int { return 2 }
|
|
|
|
func numSize(digits int, signed bool) int {
|
|
if signed {
|
|
return digits + 1
|
|
}
|
|
return digits
|
|
}
|
|
|
|
func numRequires(c *ctxConfig, ft fieldType) error {
|
|
switch ft {
|
|
case ftYear, ftMonthOfYear, ftDayOfMonth:
|
|
c.enableDate()
|
|
|
|
case ftWeekyear, ftWeekOfWeekyear:
|
|
c.enableISO()
|
|
|
|
case ftDayOfYear:
|
|
c.enableYearday()
|
|
|
|
case ftDayOfWeek:
|
|
c.enableWeekday()
|
|
|
|
case ftHalfdayOfDay,
|
|
ftHourOfHalfday,
|
|
ftClockhourOfHalfday,
|
|
ftClockhourOfDay,
|
|
ftHourOfDay,
|
|
ftMinuteOfDay,
|
|
ftMinuteOfHour,
|
|
ftSecondOfDay,
|
|
ftSecondOfMinute:
|
|
c.enableClock()
|
|
|
|
case ftMillisOfDay:
|
|
c.enableClock()
|
|
c.enableMillis()
|
|
|
|
case ftMillisOfSecond:
|
|
c.enableMillis()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (f textField) requires(c *ctxConfig) error {
|
|
switch f.ft {
|
|
case ftHalfdayOfDay:
|
|
c.enableClock()
|
|
case ftMonthOfYear:
|
|
c.enableDate()
|
|
case ftDayOfWeek:
|
|
c.enableWeekday()
|
|
default:
|
|
return fmt.Errorf("time field %v not supported by text", f.ft)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (f textField) estimateSize() int {
|
|
switch f.ft {
|
|
case ftHalfdayOfDay:
|
|
return 2
|
|
case ftDayOfWeek:
|
|
if f.short {
|
|
return 3
|
|
}
|
|
return 9 // max(weekday) = len(Wednesday)
|
|
case ftMonthOfYear:
|
|
if f.short {
|
|
return 6
|
|
}
|
|
return 9 // max(month) = len(September)
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func (r runeLiteral) compile() (prog, error) {
|
|
switch utf8.RuneLen(r.r) {
|
|
case -1:
|
|
return prog{}, errors.New("invalid rune")
|
|
}
|
|
|
|
var tmp [8]byte
|
|
l := utf8.EncodeRune(tmp[:], r.r)
|
|
return makeCopy(tmp[:l])
|
|
}
|
|
|
|
func (s stringLiteral) compile() (prog, error) {
|
|
return makeCopy([]byte(s.s))
|
|
}
|
|
|
|
func (n unpaddedNumber) compile() (prog, error) {
|
|
return makeProg(opNum, byte(n.ft))
|
|
}
|
|
|
|
func (n paddedNumber) compile() (prog, error) {
|
|
if n.div == 0 {
|
|
return makeProg(opNumPadded, byte(n.ft), byte(n.maxDigits))
|
|
}
|
|
return makeProg(opExtNumPadded, byte(n.ft), byte(n.div), byte(n.maxDigits))
|
|
}
|
|
|
|
func (n twoDigitYear) compile() (prog, error) {
|
|
return makeProg(opTwoDigit, byte(n.ft))
|
|
}
|
|
|
|
func (f textField) compile() (prog, error) {
|
|
if f.short {
|
|
return makeProg(opTextShort, byte(f.ft))
|
|
}
|
|
return makeProg(opTextLong, byte(f.ft))
|
|
}
|
|
|
|
func (p paddingZeros) requires(c *ctxConfig) error { return nil }
|
|
func (p paddingZeros) estimateSize() int { return p.count }
|
|
func (p paddingZeros) compile() (prog, error) {
|
|
return makeProg(opZeros, byte(p.count))
|
|
}
|