Body:
This commit introduces two key improvements to the `vals` package:
1. **Optimized `CreateCValue` type switch:**
The `type switch` statement in `CreateCValue` has been reordered to prioritize common `CValue` forms (direct value, pointer, slice, function) and then by the frequency of the underlying base types (e.g., `string`, `int`, `bool`). This structure improves readability and potentially runtime performance by hitting more frequent cases earlier.
2. **Added `CValueType.String()` method:**
A `String()` method has been added to the `CValueType` type. This method provides a human-readable string representation of a `CValueType`, correctly handling base types, list types (e.g., `[]string`), map types (e.g., `map[int]string`), and object types (`object` or `object(MyStruct)`). This enhances debugging and logging capabilities.
No new external functions (like `IsListOf` or `IsMapValueOf`) were added, focusing solely on the requested internal refactorings and the `String()` method for `CValueType`.
master
parent
f3d4502763
commit
66db3529f2
@ -0,0 +1,95 @@
|
||||
// =============================================================================
|
||||
// Active-GO Framework
|
||||
// Copyright (c) 2025 ActiveThing (https://activething.com)
|
||||
// Author: Juan V. Navarro juanvnl@activething.com
|
||||
// =============================================================================
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =============================================================================
|
||||
// Date Create 13/05/2025
|
||||
// =============================================================================
|
||||
|
||||
// Package excs provides utilities for capturing and working with execution contexts,
|
||||
// primarily focused on stack traces. This package is used by the errs package
|
||||
// to include stack trace information in structured errors.
|
||||
package excs
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Constants used for stack trace configuration and handling.
|
||||
const (
|
||||
// stackSkipFrames defines how many initial frames are skipped when capturing the stack.
|
||||
// 2 frames are skipped to exclude internal system calls (runtime.Callers and this function).
|
||||
stackSkipFrames = 2
|
||||
|
||||
// stackMaxFrames defines the maximum number of frames that will be captured.
|
||||
// Limits the depth of the stack trace to 32 frames by default.
|
||||
stackMaxFrames = 32
|
||||
)
|
||||
|
||||
// Stack is a slice of program counters, representing a captured stack trace.
|
||||
type Stack []uintptr
|
||||
|
||||
// CreateStack captures the current execution stack trace.
|
||||
// It takes an offset (number of frames to skip in addition to the default)
|
||||
// and maxFrames (maximum number of frames to capture).
|
||||
// Returns a Stack slice containing the captured program counters.
|
||||
func CreateStack(options ...int) Stack {
|
||||
offset := 0
|
||||
maxFrames := stackMaxFrames
|
||||
if len(options) > 0 {
|
||||
offset = options[0]
|
||||
if offset < 0 {
|
||||
offset = 0
|
||||
}
|
||||
if len(options) > 1 {
|
||||
maxFrames = options[1]
|
||||
if maxFrames < 0 || maxFrames > stackMaxFrames {
|
||||
maxFrames = stackMaxFrames
|
||||
}
|
||||
}
|
||||
}
|
||||
ls := make([]uintptr, maxFrames)
|
||||
|
||||
// Capture the stack trace using runtime.Callers.
|
||||
// runtime.Callers fills the slice 'ls' with program counters,
|
||||
// skipping 'offset + stackSkipFrames' frames.
|
||||
// 'cn' will contain the actual number of frames captured.
|
||||
cn := runtime.Callers(offset+stackSkipFrames, ls)
|
||||
|
||||
// Return only the slice containing valid program counters (up to 'cn').
|
||||
return ls[:cn]
|
||||
}
|
||||
|
||||
// Frames converts the Stack (slice of program counters) into a slice of StackFrame objects.
|
||||
// Each StackFrame provides detailed information about a single frame in the stack.
|
||||
func (s Stack) Frames() []StackFrame {
|
||||
// Create a slice to store StackFrame objects with the same length as the stack.
|
||||
f := make([]StackFrame, len(s))
|
||||
|
||||
// Convert each program counter to a StackFrame object.
|
||||
for i, p := range s {
|
||||
f[i] = CreateStackFrame(p)
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
@ -0,0 +1,149 @@
|
||||
// =============================================================================
|
||||
// Active-GO Framework
|
||||
// Copyright (c) 2025 ActiveThing (https://activething.com)
|
||||
// Author: Juan V. Navarro juanvnl@activething.com
|
||||
// =============================================================================
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =============================================================================
|
||||
// Date Create 13/05/2025
|
||||
// =============================================================================
|
||||
|
||||
package excs
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// stackUnknownInfo is the default value when information about a stack frame cannot be obtained.
|
||||
stackUnknownInfo = "???"
|
||||
)
|
||||
|
||||
type (
|
||||
// StackFrame represents a single frame in a stack trace.
|
||||
// It contains detailed information about the function call at that point.
|
||||
StackFrame struct {
|
||||
// LineNumber is the line number in the source file where this frame was created.
|
||||
LineNumber int
|
||||
|
||||
// File is the full path to the source file containing this frame.
|
||||
File string
|
||||
|
||||
// FuncName is the name of the function where this frame was created,
|
||||
// with any receiver types removed.
|
||||
FuncName string
|
||||
|
||||
// Package is the full package path where this frame was created.
|
||||
Package string
|
||||
|
||||
// Counter is the program counter address for this frame.
|
||||
Counter uintptr
|
||||
|
||||
// files is an internal cache of file contents.
|
||||
// Note: This field is present but not used in the current implementation of SourceLine.
|
||||
files map[string][]byte
|
||||
}
|
||||
)
|
||||
|
||||
// CreateStackFrame creates a new StackFrame from a program counter address.
|
||||
// It uses runtime information to populate the frame details.
|
||||
// Returns an empty StackFrame if the counter is 0.
|
||||
func CreateStackFrame(counter uintptr) StackFrame {
|
||||
sf := StackFrame{}
|
||||
if counter == 0 {
|
||||
return sf
|
||||
}
|
||||
sf.Counter = counter
|
||||
// Get runtime.Func for the program counter.
|
||||
fn := runtime.FuncForPC(counter)
|
||||
// Extract package and function name.
|
||||
sf.Package, sf.FuncName = packageAndName(fn)
|
||||
// Get file and line number. Note: counter - 1 is used to get the call site.
|
||||
sf.File, sf.LineNumber = fn.FileLine(counter - 1)
|
||||
return sf
|
||||
}
|
||||
|
||||
// SourceLine attempts to retrieve the source code line for this stack frame.
|
||||
// It reads the source file and returns the content of the line specified by LineNumber.
|
||||
// Returns stackUnknownInfo if the line number is invalid or an error occurs while reading the file.
|
||||
func (f StackFrame) SourceLine() (string, error) {
|
||||
// Return unknown info if line number is not valid.
|
||||
if f.LineNumber <= 0 {
|
||||
return stackUnknownInfo, nil
|
||||
}
|
||||
// Open the source file.
|
||||
file, err := os.Open(f.File)
|
||||
if err != nil {
|
||||
return "", err // Return error if file cannot be opened.
|
||||
}
|
||||
defer func(file *os.File) {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
//todo
|
||||
}
|
||||
}(file) // Ensure the file is closed.
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
currentLine := 1
|
||||
// Scan the file line by line.
|
||||
for scanner.Scan() {
|
||||
// If the current line matches the frame's line number.
|
||||
if currentLine == f.LineNumber {
|
||||
// Return the trimmed line content as a string.
|
||||
return string(bytes.Trim(scanner.Bytes(), " \t")), nil
|
||||
}
|
||||
currentLine++
|
||||
}
|
||||
|
||||
// Check for scanner errors.
|
||||
if err := scanner.Err(); err != nil {
|
||||
return "", err // Return scanner error.
|
||||
}
|
||||
|
||||
// If the line number was not found (e.g., file shorter than expected).
|
||||
return stackUnknownInfo, nil
|
||||
}
|
||||
|
||||
// packageAndName extracts the package path and function name from a runtime.Func.
|
||||
// It handles different naming conventions, including methods.
|
||||
func packageAndName(fn *runtime.Func) (string, string) {
|
||||
nm := fn.Name() // Get the full name, e.g., "main.(*MyType).MyMethod" or "main.myFunction"
|
||||
pg := "" // Initialize package path
|
||||
|
||||
// Find the last slash, which separates package path components.
|
||||
if ls := strings.LastIndex(nm, "/"); ls >= 0 {
|
||||
pg = nm[:ls] + "/" // Extract the path part
|
||||
nm = nm[ls+1:] // Keep the rest of the name
|
||||
}
|
||||
|
||||
// Find the first dot after the last slash, which separates package name from function name.
|
||||
if pd := strings.Index(nm, "."); pd >= 0 {
|
||||
pg += nm[:pd] // Add the package name to the path
|
||||
nm = nm[pd+1:] // Keep the function name
|
||||
}
|
||||
|
||||
// Replace the Go internal method separator '·' with '.' for readability.
|
||||
return pg, strings.Replace(nm, "·", ".", -1)
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
// =============================================================================
|
||||
// GO·AT Framework
|
||||
// Copyright (c) 2025 ActiveThing (https://activething.com)
|
||||
// Author: Juan V. Navarro juanvnl@activething.com
|
||||
// =============================================================================
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =============================================================================
|
||||
// Date Create 29/05/2025
|
||||
// =============================================================================
|
||||
|
||||
package vals
|
||||
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
g = struct {
|
||||
minTime,
|
||||
maxTime time.Time
|
||||
|
||||
cValueTypeInfos [maxCValueTypes]cValueTypeInfo
|
||||
}{
|
||||
minTime: time.Unix(0, math.MinInt64),
|
||||
maxTime: time.Unix(0, math.MaxInt64),
|
||||
|
||||
cValueTypeInfos: createCValueTypeInfos(),
|
||||
}
|
||||
)
|
||||
Loading…
Reference in new issue