// ------------------------------------------------------------------------ // Project atila // Active Thing (activething.com) git.activething.com/go // // File name f.go // Created by DEV // Modified 29/01/2024 // // Copyright 2024 activething.com // ------------------------------------------------------------------------ // 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 apack import ( "bits" "reflect" "strings" "time" "unicode" ) const ( FlagOmit Flags = 1 << iota FlagOmitEmpty FlagQuote FlagScapeHTML FlagString FlagEncrypted FlagBinary64 Flags = 0b0000100000000000 FlagBinary32 Flags = 0b0000010000000000 flagMaskBin Flags = 0b0000110000000000 FlagDateRFC822 Flags = 0b0001000000000000 FlagDateUnix Flags = 0b0010000000000000 FlagDateANSIC Flags = 0b0100000000000000 FlagDateRFC850 Flags = 0b1000000000000000 flagMaskDate Flags = 0b1111000000000000 ) type Flags bits.BFlags16 func (f Flags) Omit () bool { return f&FlagOmit != 0 } func (f Flags) OmitEmpty () bool { return f&FlagOmitEmpty != 0 } func (f Flags) Quote () bool { return f&FlagQuote != 0 } func (f Flags) EscapeHTML () bool { return f&FlagScapeHTML != 0 } func (f Flags) String () bool { return f&FlagString != 0 } func (f Flags) Encrypted() bool { return f&FlagEncrypted != 0 } func (f Flags) Binary () bool { return f&(FlagBinary64|FlagBinary32) != 0 } func (f Flags) Bin64 () bool { return f&FlagBinary64 != 0 } func (f Flags) Bin32 () bool { return f&FlagBinary32 != 0 } func (f Flags) SetDate (flagDate Flags) Flags { return (f&flagMaskDate) | flagDate } func (f Flags) SetBinary (flagBinary Flags) Flags { return (f&flagMaskBin) | flagBinary } func (f Flags) Names () string { var ls []string if f&FlagOmit != 0 { ls = append(ls,"omit")} if f&FlagOmitEmpty != 0 { ls = append(ls,"omitempty")} if f&FlagQuote != 0 { ls = append(ls,"quote")} if f&FlagScapeHTML != 0 { ls = append(ls,"html")} if f&FlagString != 0 { ls = append(ls,"string")} if f&flagMaskBin != 0 { ls = append(ls,f.binName()) } if f&flagMaskDate != 0 { ls = append(ls,f.dateName()) } if len(ls) > 0 { return strings.Join(ls,",") } return "" } func (f Flags) binName () string { switch f & flagMaskBin { case FlagBinary64 : return "b64" case FlagBinary32 : return "b32" } return "" } func (f Flags) dateName() string { switch f & flagMaskDate { case FlagDateUnix : return "unix" case FlagDateRFC822: return "rfc822" case FlagDateANSIC : return "ansic" case FlagDateRFC850: return "rfc8550" default: return "rfc822z" } } func (f Flags) DateFormat () string { switch f & flagMaskDate { case FlagDateUnix : return time.UnixDate case FlagDateRFC822: return time.RFC822 case FlagDateANSIC : return time.ANSIC case FlagDateRFC850: return time.RFC850 default: return time.RFC822Z } } func FlagByName (flag string) (f Flags) { switch strings.ToLower(flag) { case "-","omit" : return FlagOmit case "o","omitempty": return FlagOmitEmpty case "q","quote" : return FlagQuote case "h","html" : return FlagScapeHTML case "s","string" : return FlagString case "e","encrypted": return FlagEncrypted // formato binario case "b64","bin64" : return FlagBinary64 case "b32","bin32" : return FlagBinary32 // formatos de fechas case "unix" : return FlagDateUnix case "rfc822" : return FlagDateRFC822 case "ansic" : return FlagDateANSIC case "rfc850" : return FlagDateRFC850 case "rfc822z": return 0 default: return 0 } } func FlagsWithNames(flags ... string) Flags { var f Flags for _,n := range flags { f |= FlagByName(n) } return f } func FlagsWithString(flags string, onOption func(string) Flags) Flags { var f Flags if len(flags) == 0 { return f } nf := f for flags != "" { var op string op,flags,_ = strings.Cut(flags,",") nf |= onOption(op) } return nf } func FlagsFromPackTag (raw reflect.StructTag) (string,Flags,bool) { return FlagsFromTag(raw,TagKey,FlagByName) } func FlagsFromTag(raw reflect.StructTag, tag string, onOption func(string) Flags) (string,Flags,bool) { st,ok := raw.Lookup(tag) if !ok { return "",0,false } nm,op,_ := strings.Cut(st,",") return nm,FlagsWithString(op,onOption),true } func CheckTag(tag string) bool { if tag == "" { return false } for _, c := range tag { switch { case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c): case !unicode.IsLetter(c) && !unicode.IsDigit(c): return false } } return true }