feat: publish the Sandwich Hime source preview
Signed-off-by: Cole Speelman <gamertan@noreply.localhost>
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package sando is the small production runtime for code generated by Hime-san.
|
||||
// It contains rendering contracts and context-specific output helpers, but no
|
||||
// router, HTTP server, middleware, or development tooling.
|
||||
package sando
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// ABI identifies the generated-code contract implemented by this version of
|
||||
// the runtime. Generated files should reference this constant so that their
|
||||
// expected ABI is visible to readers and tooling.
|
||||
const ABI = "sando.v1"
|
||||
|
||||
// RuntimeABI is a descriptive alias for ABI.
|
||||
const RuntimeABI = ABI
|
||||
|
||||
var (
|
||||
// ErrNilComponent is returned when Render is asked to render a nil
|
||||
// component, including a typed nil held in a Component interface.
|
||||
ErrNilComponent = errors.New("sando: nil component")
|
||||
// ErrNilContext is returned when a component is rendered with a nil
|
||||
// context.Context.
|
||||
ErrNilContext = errors.New("sando: nil context")
|
||||
// ErrNilWriter is returned when a component is rendered with a nil writer.
|
||||
ErrNilWriter = errors.New("sando: nil writer")
|
||||
)
|
||||
|
||||
// Component is the complete production rendering contract. Components are
|
||||
// values rather than HTTP handlers so applications retain ownership of
|
||||
// buffering, routing, headers, status codes, and error policy.
|
||||
type Component interface {
|
||||
Render(context.Context, io.Writer) error
|
||||
}
|
||||
|
||||
// ComponentFunc adapts a function to Component.
|
||||
type ComponentFunc func(context.Context, io.Writer) error
|
||||
|
||||
// Render calls f with ctx and w.
|
||||
func (f ComponentFunc) Render(ctx context.Context, w io.Writer) error {
|
||||
if f == nil {
|
||||
return ErrNilComponent
|
||||
}
|
||||
if ctx == nil {
|
||||
return ErrNilContext
|
||||
}
|
||||
if isNil(w) {
|
||||
return ErrNilWriter
|
||||
}
|
||||
return f(ctx, w)
|
||||
}
|
||||
|
||||
// Render renders component into w. It reports nil inputs as errors rather than
|
||||
// panicking, including typed nil component and writer values.
|
||||
func Render(ctx context.Context, w io.Writer, component Component) error {
|
||||
if ctx == nil {
|
||||
return ErrNilContext
|
||||
}
|
||||
if isNil(w) {
|
||||
return ErrNilWriter
|
||||
}
|
||||
if isNil(component) {
|
||||
return ErrNilComponent
|
||||
}
|
||||
return component.Render(ctx, w)
|
||||
}
|
||||
|
||||
// isNil recognizes typed nil values stored in interfaces. It is intentionally
|
||||
// confined to API boundary validation and is not a component registry.
|
||||
func isNil(value any) bool {
|
||||
if value == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
rv := reflect.ValueOf(value)
|
||||
switch rv.Kind() {
|
||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice:
|
||||
return rv.IsNil()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user