delve/vendor/github.com/google/go-dap/codec.go
2023-11-04 17:07:55 +01:00

189 lines
6.4 KiB
Go

// Copyright 2020 Google LLC
//
// 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
//
// https://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.
// This file contains utilities for decoding JSON-encoded bytes into DAP message.
package dap
import (
"encoding/json"
"fmt"
)
// DecodeProtocolMessageFieldError describes which JSON attribute
// has an unsupported value that the decoding cannot handle.
type DecodeProtocolMessageFieldError struct {
Seq int
SubType string
FieldName string
FieldValue string
Message json.RawMessage
}
func (e *DecodeProtocolMessageFieldError) Error() string {
return fmt.Sprintf("%s %s '%s' is not supported (seq: %d)", e.SubType, e.FieldName, e.FieldValue, e.Seq)
}
// defaultCodec is used to decode vanilla DAP messages.
var defaultCodec = NewCodec()
// Codec is responsible for turning byte blobs into DAP messages.
type Codec struct {
eventCtor map[string]messageCtor
requestCtor map[string]messageCtor
responseCtor map[string]messageCtor
}
// NewCodec constructs a new codec that extends the vanilla DAP protocol.
// Unless you need to register custom DAP messages, use
// DecodeProtocolMessage instead.
func NewCodec() *Codec {
ret := &Codec{
eventCtor: make(map[string]messageCtor),
requestCtor: make(map[string]messageCtor),
responseCtor: make(map[string]messageCtor),
}
for k, v := range eventCtor {
ret.eventCtor[k] = v
}
for k, v := range requestCtor {
ret.requestCtor[k] = v
}
for k, v := range responseCtor {
ret.responseCtor[k] = v
}
return ret
}
// RegisterRequest registers a new custom DAP command, so that it can be
// unmarshalled by DecodeMessage. Returns an error when the command already
// exists.
//
// The ctor functions need to return a new instance of the underlying DAP
// message type. A typical usage looks like this:
//
// reqCtor := func() Message { return &LaunchRequest{} }
// respCtor := func() Message { return &LaunchResponse{} }
// codec.RegisterRequest("launch", reqCtor, respCtor)
func (c *Codec) RegisterRequest(command string, requestCtor, responseCtor func() Message) error {
_, hasReqCtor := c.requestCtor[command]
_, hasRespCtor := c.responseCtor[command]
if hasReqCtor || hasRespCtor {
return fmt.Errorf("command %q is already registered", command)
}
c.requestCtor[command] = requestCtor
c.responseCtor[command] = responseCtor
return nil
}
// RegisterEvent registers a new custom DAP event, so that it can be
// unmarshalled by DecodeMessage. Returns an error when the event already
// exists.
//
// The ctor function needs to return a new instance of the underlying DAP
// message type. A typical usage looks like this:
//
// ctor := func() Message { return &StoppedEvent{} }
// codec.RegisterEvent("stopped", ctor)
func (c *Codec) RegisterEvent(event string, ctor func() Message) error {
if _, hasEventCtor := c.eventCtor[event]; hasEventCtor {
return fmt.Errorf("event %q is already registered", event)
}
c.eventCtor[event] = ctor
return nil
}
// DecodeMessage parses the JSON-encoded data and returns the result of
// the appropriate type within the ProtocolMessage hierarchy. If message type,
// command, etc cannot be cast, returns DecodeProtocolMessageFieldError.
// See also godoc for json.Unmarshal, which is used for underlying decoding.
func (c *Codec) DecodeMessage(data []byte) (Message, error) {
// This struct is the union of the ResponseMessage, RequestMessage, and
// EventMessage types. It is an optimization that saves an additional
// json.Unmarshal call.
var m struct {
ProtocolMessage
Command string `json:"command"`
Event string `json:"event"`
Success bool `json:"success"`
}
if err := json.Unmarshal(data, &m); err != nil {
return nil, err
}
switch m.Type {
case "request":
return c.decodeRequest(m.Command, m.Seq, data)
case "response":
return c.decodeResponse(m.Command, m.Seq, m.Success, data)
case "event":
return c.decodeEvent(m.Event, m.Seq, data)
default:
return nil, &DecodeProtocolMessageFieldError{m.Seq, "ProtocolMessage", "type", m.Type, json.RawMessage(data)}
}
}
// decodeRequest determines what request type in the ProtocolMessage hierarchy
// data corresponds to and uses json.Unmarshal to populate the corresponding
// struct to be returned.
func (c *Codec) decodeRequest(command string, seq int, data []byte) (Message, error) {
ctor, ok := c.requestCtor[command]
if !ok {
return nil, &DecodeProtocolMessageFieldError{seq, "Request", "command", command, json.RawMessage(data)}
}
requestPtr := ctor()
err := json.Unmarshal(data, requestPtr)
return requestPtr, err
}
// decodeResponse determines what response type in the ProtocolMessage hierarchy
// data corresponds to and uses json.Unmarshal to populate the corresponding
// struct to be returned.
func (c *Codec) decodeResponse(command string, seq int, success bool, data []byte) (Message, error) {
if !success {
var er ErrorResponse
err := json.Unmarshal(data, &er)
return &er, err
}
ctor, ok := c.responseCtor[command]
if !ok {
return nil, &DecodeProtocolMessageFieldError{seq, "Response", "command", command, json.RawMessage(data)}
}
responsePtr := ctor()
err := json.Unmarshal(data, responsePtr)
return responsePtr, err
}
// decodeEvent determines what event type in the ProtocolMessage hierarchy
// data corresponds to and uses json.Unmarshal to populate the corresponding
// struct to be returned.
func (c *Codec) decodeEvent(event string, seq int, data []byte) (Message, error) {
ctor, ok := c.eventCtor[event]
if !ok {
return nil, &DecodeProtocolMessageFieldError{seq, "Event", "event", event, json.RawMessage(data)}
}
eventPtr := ctor()
err := json.Unmarshal(data, eventPtr)
return eventPtr, err
}
// DecodeProtocolMessage parses the JSON-encoded ProtocolMessage and returns
// the message embedded in it. If message type, command, etc cannot be cast,
// returns DecodeProtocolMessageFieldError. See also godoc for json.Unmarshal,
// which is used for underlying decoding.
func DecodeProtocolMessage(data []byte) (Message, error) {
return defaultCodec.DecodeMessage(data)
}
type messageCtor func() Message