package policy import ( "fmt" "strconv" "strings" "github.com/nspcc-dev/neofs-api-go/v2/netmap" ) func Encode(p *netmap.PlacementPolicy) []string { if p == nil { return nil } var ( replicas = p.GetReplicas() selectors = p.GetSelectors() filters = p.GetFilters() ) // 1 for container backup factor result := make([]string, 0, len(replicas)+len(selectors)+len(filters)+1) // first print replicas encodeReplicas(replicas, &result) // then backup factor if backupFactor := p.GetContainerBackupFactor(); backupFactor != 0 { result = append(result, fmt.Sprintf("CBF %d", backupFactor)) } // then selectors encodeSelectors(selectors, &result) // then filters encodeFilters(filters, &result) return result } func encodeReplicas(replicas []*netmap.Replica, dst *[]string) { builder := new(strings.Builder) for _, replica := range replicas { builder.WriteString("REP ") builder.WriteString(strconv.FormatUint(uint64(replica.GetCount()), 10)) if s := replica.GetSelector(); s != "" { builder.WriteString(" IN ") builder.WriteString(s) } *dst = append(*dst, builder.String()) builder.Reset() } } func encodeSelectors(selectors []*netmap.Selector, dst *[]string) { builder := new(strings.Builder) for _, selector := range selectors { builder.WriteString("SELECT ") builder.WriteString(strconv.FormatUint(uint64(selector.GetCount()), 10)) if a := selector.GetAttribute(); a != "" { builder.WriteString(" IN") switch selector.GetClause() { case netmap.Same: builder.WriteString(" SAME ") case netmap.Distinct: builder.WriteString(" DISTINCT ") default: builder.WriteString(" ") } builder.WriteString(a) } if f := selector.GetFilter(); f != "" { builder.WriteString(" FROM ") builder.WriteString(f) } if n := selector.GetName(); n != "" { builder.WriteString(" AS ") builder.WriteString(n) } *dst = append(*dst, builder.String()) builder.Reset() } } func encodeFilters(filters []*netmap.Filter, dst *[]string) { builder := new(strings.Builder) for _, filter := range filters { builder.WriteString("FILTER ") builder.WriteString(encodeFilter(filter)) *dst = append(*dst, builder.String()) builder.Reset() } } func operationString(operation netmap.Operation) string { switch operation { case netmap.EQ: return "EQ" case netmap.NE: return "NE" case netmap.GT: return "GT" case netmap.GE: return "GE" case netmap.LT: return "LT" case netmap.LE: return "LE" case netmap.OR: return "OR" case netmap.AND: return "AND" default: return "" } } func encodeFilter(filter *netmap.Filter) string { builder := new(strings.Builder) unspecified := filter.GetOp() == netmap.UnspecifiedOperation if k := filter.GetKey(); k != "" { builder.WriteString(k) builder.WriteString(" ") builder.WriteString(operationString(filter.GetOp())) builder.WriteString(" ") builder.WriteString(filter.GetValue()) } else if n := filter.GetName(); unspecified && n != "" { builder.WriteString("@") builder.WriteString(n) } for i, subfilter := range filter.GetFilters() { if i != 0 { builder.WriteString(" ") builder.WriteString(operationString(filter.GetOp())) builder.WriteString(" ") } builder.WriteString(encodeFilter(subfilter)) } if n := filter.GetName(); n != "" && !unspecified { builder.WriteString(" AS ") builder.WriteString(n) } return builder.String() }