blob: 29c83156cb731fd09d57e024c5d63e85950a941d [file] [log] [blame]
// Copyright 2022 The LUCI Authors.
//
// 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 protowalk contains routines for efficiently walking proto messages,
// focusing on the ability to react to field annotations.
//
// This package defines an interface (FieldProcessor) which you can
// implement to react to any fields you like.
//
// This package also comes with stock implementations for the following common
// field annotations:
// - google.api.field_behavior = REQUIRED
// - google.api.field_behavior = OUTPUT_ONLY
// - deprecated = true
//
// # How it works
//
// 1. Register a FieldProcessor using RegisterFieldProcessor.
//
// A FieldProcessor checks and/or manipulates fields in a proto message. When
// registering an implementation, you also provide a `selector` function which
// detects fields (e.g. by their type, field options, etc.) that the
// FieldProcessor wants to operate on.
//
// 2. Use the Fields() with one or more FieldProcessor instantances to process
// a proto message.
//
// Fields generates, once per process, a global cache entry keyed on
// (msgType, processorType). This entry is a list of fields in `msgType`
// which the FieldProcessor's registered `selector` function says it should
// operate on, and also indicates for a given field if it should be recursed
// for this processor (i.e. if field `M.a` is a message type `A` which has
// fields that match this processor).
//
// Once the cache entries are generated, Fields then generates a 'plan' which is
// the combination of _all_ the provided processors' cache entries, such that
// Fields() can then walk through all affected fields, once, in order,
// generating results from the provided message in an ordered and deterministic
// fashion.
//
// The upshot is that Fields() should be O(CheckableFields), no matter how big
// the proto messages are, rather than a naive O(Fields) implementation.
//
// A Result contains the ProtoPath and a message generated by the
// FieldProcessor. The ProtoPath describes the path through the source message
// to the affected field, and can either be printed for display, or can be used
// to retrieve the actual value.
package protowalk