#!/usr/bin/env bash # # Generate concrete implementations of LatestMap. # # e.g. # $ generate_latest_map ./report/out.go string NodeControlData ... # # Depends on: # - gofmt function generate_header { local out_file="${1}" local cmd="${2}" cat << EOF >"${out_file}" // Generated file, do not edit. // To regenerate, run ${cmd} package report import ( "time" "github.com/ugorji/go/codec" ) EOF } function generate_latest_map { local out_file="$1" local data_type="$2" local uppercase_data_type="${data_type^}" local lowercase_data_type="${data_type,}" local wire_entry_type="wire${uppercase_data_type}LatestEntry" local decoder_type="${lowercase_data_type}LatestEntryDecoder" local iface_decoder_variable="${uppercase_data_type}LatestEntryDecoder" local latest_map_type="${uppercase_data_type}LatestMap" local empty_latest_map_variable="Empty${latest_map_type}" local make_function="Make${latest_map_type}" local json_timestamp='`json:"timestamp"`' local json_value='`json:"value"`' cat << EOF >>"${out_file}" type ${wire_entry_type} struct { Timestamp time.Time ${json_timestamp} Value ${data_type} ${json_value} } type ${decoder_type} struct {} func (d *${decoder_type}) Decode(decoder *codec.Decoder, entry *LatestEntry) { wire := ${wire_entry_type}{} decoder.Decode(&wire) entry.Timestamp = wire.Timestamp entry.Value = wire.Value } // ${iface_decoder_variable} is an implementation of LatestEntryDecoder // that decodes the LatestEntry instances having a ${data_type} value. var ${iface_decoder_variable} LatestEntryDecoder = &${decoder_type}{} // ${latest_map_type} holds latest ${data_type} instances. type ${latest_map_type} LatestMap // ${empty_latest_map_variable} is an empty ${latest_map_type}. Start with this. var ${empty_latest_map_variable} = (${latest_map_type})(MakeLatestMapWithDecoder(${iface_decoder_variable})) // ${make_function} makes an empty ${latest_map_type}. func ${make_function}() ${latest_map_type} { return ${empty_latest_map_variable} } // Copy is a noop, as ${latest_map_type}s are immutable. func (m ${latest_map_type}) Copy() ${latest_map_type} { return (${latest_map_type})((LatestMap)(m).Copy()) } // Size returns the number of elements. func (m ${latest_map_type}) Size() int { return (LatestMap)(m).Size() } // Merge produces a fresh ${latest_map_type} containing the keys from both inputs. // When both inputs contain the same key, the newer value is used. func (m ${latest_map_type}) Merge(other ${latest_map_type}) ${latest_map_type} { return (${latest_map_type})((LatestMap)(m).Merge((LatestMap)(other))) } // Lookup the value for the given key. func (m ${latest_map_type}) Lookup(key string) (${data_type}, bool) { v, ok := (LatestMap)(m).Lookup(key) if !ok { var zero ${data_type} return zero, false } return v.(${data_type}), true } // LookupEntry returns the raw entry for the given key. func (m ${latest_map_type}) LookupEntry(key string) (${data_type}, time.Time, bool) { v, timestamp, ok := (LatestMap)(m).LookupEntry(key) if !ok { var zero ${data_type} return zero, timestamp, false } return v.(${data_type}), timestamp, true } // Set the value for the given key. func (m ${latest_map_type}) Set(key string, timestamp time.Time, value ${data_type}) ${latest_map_type} { return (${latest_map_type})((LatestMap)(m).Set(key, timestamp, value)) } // Delete the value for the given key. func (m ${latest_map_type}) Delete(key string) ${latest_map_type} { return (${latest_map_type})((LatestMap)(m).Delete(key)) } // ForEach executes fn on each key value pair in the map. func (m ${latest_map_type}) ForEach(fn func(k string, timestamp time.Time, v ${data_type})) { (LatestMap)(m).ForEach(func(key string, ts time.Time, value interface{}) { fn(key, ts, value.(${data_type})) }) } // String returns the ${latest_map_type}'s string representation. func (m ${latest_map_type}) String() string { return (LatestMap)(m).String() } // DeepEqual tests equality with other ${latest_map_type}. func (m ${latest_map_type}) DeepEqual(n ${latest_map_type}) bool { return (LatestMap)(m).DeepEqual((LatestMap)(n)) } // CodecEncodeSelf implements codec.Selfer. func (m *${latest_map_type}) CodecEncodeSelf(encoder *codec.Encoder) { (*LatestMap)(m).CodecEncodeSelf(encoder) } // CodecDecodeSelf implements codec.Selfer. func (m *${latest_map_type}) CodecDecodeSelf(decoder *codec.Decoder) { bm := (*LatestMap)(m) bm.decoder = ${iface_decoder_variable} bm.CodecDecodeSelf(decoder) } // MarshalJSON shouldn't be used, use CodecEncodeSelf instead. func (${latest_map_type}) MarshalJSON() ([]byte, error) { panic("MarshalJSON shouldn't be used, use CodecEncodeSelf instead") } // UnmarshalJSON shouldn't be used, use CodecDecodeSelf instead. func (*${latest_map_type}) UnmarshalJSON(b []byte) error { panic("UnmarshalJSON shouldn't be used, use CodecDecodeSelf instead") } EOF } if [ -z "${1}" ]; then echo "No output file given" exit 1 fi out="${1}" outtmp="${out}.tmp" generate_header "${outtmp}" "${0} ${*}" shift for t in ${*}; do generate_latest_map "${outtmp}" "${t}" done gofmt -s -w "${outtmp}" mv "${outtmp}" "${out}"