Documentation
¶
Overview ¶
Package types defines the CalcMark type system.
CalcMark supports several value types for calculations and data representation. All types implement the Type interface which provides string representation.
Core Types ¶
- Number: Arbitrary-precision decimal numbers
- Currency: Monetary values with currency symbol/code
- Quantity: Physical quantities with units (e.g., "5 kg", "10 meters")
- Date: Calendar dates with date arithmetic
- Time: Time of day with timezone support
- Duration: Time durations (e.g., "5 days", "3 hours")
- Boolean: True/false values
Number Type ¶
Numbers use arbitrary-precision decimals via shopspring/decimal:
num := types.NewNumber(decimal.NewFromFloat(3.14159)) fmt.Println(num.String()) // "3.14159"
Supports thousands separators:
1,000 1_000_000
Currency Type ¶
Currency values combine a decimal amount with a symbol or ISO code:
usd := types.NewCurrency(decimal.NewFromInt(100), "$") eur := types.NewCurrencyFromCode(decimal.NewFromInt(50), "EUR")
Supported symbols: $, €, £, ¥ Supports ISO 4217 currency codes (e.g., USD, EUR, GBP, JPY)
Quantity Type ¶
Physical quantities with units:
mass := types.NewQuantity(decimal.NewFromInt(5), "kg") length := types.NewQuantity(decimal.NewFromInt(10), "meters")
Supports SI and US customary units:
- Length: meters, feet, kilometers, miles, etc.
- Mass: kilograms, pounds, grams, etc.
- Volume: liters, gallons, cups, etc.
Date Type ¶
Calendar dates with arithmetic operations:
today := types.NewDateFromTime(time.Now()) nextWeek := today.AddDays(7) daysBetween := today.DaysBetween(nextWeek) // 7
Time Type ¶
Time of day with timezone support:
morning := types.NewTime(9, 30, 0, false, 0) // 9:30 AM UTC evening := types.NewTime(6, 0, 0, true, -300) // 6:00 PM EST
Duration Type ¶
Time durations for date arithmetic:
week := types.NewDuration(7, types.DurationUnitDay) hour := types.NewDuration(1, types.DurationUnitHour)
Boolean Type ¶
Simple true/false values:
t := types.NewBoolean(true) f := types.NewBoolean(false)
Type Conversions ¶
The type system maintains type safety while allowing sensible conversions:
- Currency + Number → Currency (preserves currency)
- Currency + Currency (different) → Number (drops units)
- Quantity + Quantity (compatible) → Quantity (first unit wins)
Performance ¶
All type operations are designed for speed and use efficient decimal arithmetic. String formatting is optimized for display/debugging.
Index ¶
- Constants
- Variables
- func GetCurrencySymbol(code string) string
- func GetExamplesForType(argType ArgType) []string
- func IsCurrencyCode(s string) bool
- func IsTimeUnit(unit string) bool
- func IsValidDurationUnit(unit string) bool
- func NormalizeCurrencyCode(s string) string
- func NormalizeTimeUnit(unit string) string
- func PeriodToPeriodsPerYear(period string) (int, bool)
- func TimeUnitToSeconds(unit string) (decimal.Decimal, error)
- func ToDecimal(t Type) (decimal.Decimal, error)
- type ArgType
- type Boolean
- type Currency
- type Date
- type Duration
- type Fraction
- type FunctionSpec
- type Number
- type ParamSpec
- type Percentage
- type Quantity
- type Rate
- type Time
- type Type
- type TypeError
Constants ¶
const MaxDisplayDenominator = 1000
MaxDisplayDenominator is the threshold above which fractions fall back to decimal display.
Variables ¶
var ArgTypeExamples = map[ArgType][]string{ ArgTypeNumber: {"42", "3.14", "1000", "1e6"}, ArgTypeQuantity: {"10 meters", "5 kg", "100 MB", "2.5 liters"}, ArgTypeRate: {"10 MB/s", "60 km/h", "100 requests/second", "5 GB/day"}, ArgTypeDuration: {"2 hours", "30 minutes", "1 day", "500 ms"}, ArgTypePercentage: {"99.9%", "15%", "50%", "0.1%"}, ArgTypeString: {`"datacenter"`, `"ssd"`, `"gzip"`}, ArgTypeAny: {"<any value>"}, }
ArgTypeExamples provides example values for each argument type.
var CodeToSymbol = map[string]string{
"USD": "$",
"EUR": "€",
"GBP": "£",
"JPY": "¥",
}
CodeToSymbol maps ISO 4217 codes to display symbols. This is the reverse of SymbolToCode.
var DurationToSeconds = map[string]int64{
"second": 1,
"seconds": 1,
"minute": 60,
"minutes": 60,
"hour": 3600,
"hours": 3600,
"day": 86400,
"days": 86400,
"week": 604800,
"weeks": 604800,
"month": 2592000,
"months": 2592000,
"year": 31536000,
"years": 31536000,
}
DurationToSeconds provides conversion factors to seconds (approximate for months/years). Uses int64 for whole-second units. Milliseconds are handled separately in conversion functions.
var FunctionSpecs = map[string]FunctionSpec{ "avg": { Name: "avg", Params: []ParamSpec{ {Name: "values", Type: ArgTypeAny, Variadic: true, Examples: []string{"1, 2, 3", "10, 20", "$100, $200"}}, }, }, "sum": { Name: "sum", Params: []ParamSpec{ {Name: "values", Type: ArgTypeAny, Variadic: true, Examples: []string{"1, 2, 3", "$100, $200", "1 kg, 500 g"}}, }, }, "sqrt": { Name: "sqrt", Params: []ParamSpec{ {Name: "value", Type: ArgTypeNumber, Examples: []string{"16", "2", "100"}}, }, }, "number": { Name: "number", Params: []ParamSpec{ {Name: "value", Type: ArgTypeAny, Examples: []string{"10 kg", "$100", "25%", "42"}}, }, }, "accumulate": { Name: "accumulate", Params: []ParamSpec{ {Name: "rate", Type: ArgTypeRate, Examples: []string{"10 MB/s", "100 requests/second", "5 GB/day"}}, {Name: "duration", Type: ArgTypeDuration, Examples: []string{"1 hour", "30 minutes", "1 day"}}, }, }, "convert_rate": { Name: "convert_rate", Params: []ParamSpec{ {Name: "rate", Type: ArgTypeRate, Examples: []string{"10 MB/s", "1 GB/hour", "100 req/s"}}, {Name: "time_unit", Type: ArgTypeString, Examples: []string{`"per second"`, `"per hour"`, `"per day"`}}, }, }, "downtime": { Name: "downtime", Params: []ParamSpec{ {Name: "availability", Type: ArgTypePercentage, Examples: []string{"99.9%", "99.99%", "99%"}}, {Name: "duration", Type: ArgTypeDuration, Examples: []string{"1 year", "1 month", "1 day"}}, }, }, "rtt": { Name: "rtt", Params: []ParamSpec{ {Name: "scope", Type: ArgTypeString, Examples: quotedNames(identifiers.NetworkScopes)}, }, }, "throughput": { Name: "throughput", Params: []ParamSpec{ {Name: "network_type", Type: ArgTypeString, Examples: quotedNames(identifiers.NetworkTypes)}, }, }, "transfer_time": { Name: "transfer_time", Params: []ParamSpec{ {Name: "size", Type: ArgTypeQuantity, Examples: []string{"1 GB", "100 MB", "10 TB"}}, {Name: "scope", Type: ArgTypeString, Examples: quotedNames(identifiers.NetworkScopes)}, {Name: "network_type", Type: ArgTypeString, Examples: quotedNames(identifiers.NetworkTypes)}, }, }, "read": { Name: "read", Params: []ParamSpec{ {Name: "size", Type: ArgTypeQuantity, Examples: []string{"1 MB", "4 KB", "1 GB"}}, {Name: "storage_type", Type: ArgTypeString, Examples: quotedNames(identifiers.StorageTypes)}, }, }, "seek": { Name: "seek", Params: []ParamSpec{ {Name: "storage_type", Type: ArgTypeString, Examples: quotedNames(identifiers.StorageTypes)}, }, }, "compress": { Name: "compress", Params: []ParamSpec{ {Name: "size", Type: ArgTypeQuantity, Examples: []string{"1 MB", "100 KB", "1 GB"}}, {Name: "compression_type", Type: ArgTypeString, Examples: quotedNames(identifiers.CompressionTypes)}, }, }, "compound": { Name: "compound", Params: []ParamSpec{ {Name: "principal", Type: ArgTypeAny, Examples: []string{"1000", "$1000", "100 users"}}, {Name: "rate", Type: ArgTypePercentage, Examples: []string{"5%", "0.05", "12%"}}, {Name: "periods", Type: ArgTypeNumber, Examples: []string{"10", "12", "5"}}, {Name: "period", Type: ArgTypeString, Optional: true, Examples: []string{"monthly", "quarterly", "compounded:monthly"}}, }, }, "grow": { Name: "grow", Params: []ParamSpec{ {Name: "amount", Type: ArgTypeAny, Examples: []string{"100", "50 GB", "1000 users"}}, {Name: "increment", Type: ArgTypeAny, Examples: []string{"20 GB", "100 users", "5"}}, {Name: "periods", Type: ArgTypeNumber, Examples: []string{"12", "6", "24"}}, }, }, "depreciate": { Name: "depreciate", Params: []ParamSpec{ {Name: "value", Type: ArgTypeAny, Examples: []string{"10000", "$50000", "1000 units"}}, {Name: "rate", Type: ArgTypePercentage, Examples: []string{"20%", "0.15", "10%"}}, {Name: "periods", Type: ArgTypeNumber, Examples: []string{"5", "10", "7"}}, {Name: "salvage", Type: ArgTypeAny, Optional: true, Examples: []string{"$5000", "1000"}}, }, }, "capacity": { Name: "capacity", Params: []ParamSpec{ {Name: "demand", Type: ArgTypeRate, Examples: []string{"1000 requests/second", "10 GB/day"}}, {Name: "capacity_per_unit", Type: ArgTypeRate, Examples: []string{"100 requests/second", "1 GB/day"}}, {Name: "unit", Type: ArgTypeString, Examples: []string{`"servers"`, `"instances"`}}, {Name: "buffer", Type: ArgTypePercentage, Optional: true, Examples: []string{"20%", "50%"}}, }, }, }
FunctionSpecs defines the type signatures for all built-in functions. This is the authoritative source for parameter type information.
var SymbolToCode = map[string]string{
"$": "USD",
"€": "EUR",
"£": "GBP",
"¥": "JPY",
}
SymbolToCode maps currency symbols to their ISO 4217 codes. This allows normalization of common symbols to standard codes.
Functions ¶
func GetCurrencySymbol ¶
GetCurrencySymbol returns the display symbol for a currency code. Returns the code itself if no symbol is defined.
func GetExamplesForType ¶ added in v1.8.13
GetExamplesForType returns example values for a given argument type.
func IsCurrencyCode ¶
IsCurrencyCode checks if a string is a known currency code or symbol.
func IsTimeUnit ¶
IsTimeUnit returns true if the given unit is a valid time unit.
func IsValidDurationUnit ¶
IsValidDurationUnit checks if the unit is a valid duration unit.
func NormalizeCurrencyCode ¶
NormalizeCurrencyCode converts a symbol or code to its ISO code. Returns the original string if not recognized.
func NormalizeTimeUnit ¶
NormalizeTimeUnit converts various time unit formats to canonical form. Handles abbreviations, plurals, and adjectival forms (e.g., "monthly" → "month"). Examples: "s" → "second", "seconds" → "second", "sec" → "second", "daily" → "day"
func PeriodToPeriodsPerYear ¶
PeriodToPeriodsPerYear returns how many of the given period fit in one year. Used by growth functions to convert between annual rates and per-period rates. Returns 0 and false for unrecognized periods.
func TimeUnitToSeconds ¶
TimeUnitToSeconds returns the number of seconds in a time unit. Used for accumulation and conversion calculations. Uses the shared DurationToSeconds map from duration.go
Types ¶
type ArgType ¶ added in v1.8.13
type ArgType string
ArgType represents the semantic type expected for a function argument. This defines what kinds of values are valid for each parameter position.
const ( ArgTypeNumber ArgType = "number" // Plain number: 42, 3.14, 1e6 ArgTypeQuantity ArgType = "quantity" // Number with unit: 10 meters, 5 kg, 100 MB ArgTypeRate ArgType = "rate" // Quantity per time: 10 MB/s, 60 km/h ArgTypeDuration ArgType = "duration" // Time span: 2 hours, 30 minutes ArgTypePercentage ArgType = "percentage" // Percentage: 99.9%, 15% ArgTypeString ArgType = "string" // String literal: "datacenter", "ssd" ArgTypeAny ArgType = "any" // Any value type )
type Boolean ¶
type Boolean struct {
Value bool
}
Boolean represents a boolean value (true/false). CalcMark supports multiple boolean representations: true/false, yes/no, t/f, y/n.
func NewBoolean ¶
NewBoolean creates a new Boolean with the given value.
type Currency ¶
type Currency struct {
Value decimal.Decimal
Symbol string // Display symbol: "$", "€", "£", "¥", or ISO code like "USD"
Code string // Normalized ISO 4217 code: "USD", "EUR", "GBP", "JPY"
IsNapkin bool // true when produced by `as napkin` conversion
}
Currency represents a monetary value with a currency symbol and ISO code. It preserves both the display symbol (e.g., "$") and the normalized ISO code (e.g., "USD").
func NewCurrency ¶
NewCurrency creates a new Currency with the given value and symbol/code. If symbolOrCode is a known symbol ($, €, £, ¥), it's mapped to the ISO code. Otherwise, it's used as both the symbol and code.
func NewCurrencyFromString ¶
NewCurrencyFromString creates a Currency from a string value and symbol/code. Returns an error if the string cannot be parsed as a valid number.
func (*Currency) IsSameCurrency ¶
IsSameCurrency checks if two currencies have the same ISO code. This is used for validating currency arithmetic operations.
func (*Currency) String ¶
String returns the precise string representation with symbol and value. This is the machine-readable form used by the JSON formatter. Unlike FormatCurrency() in format/display, String() does NOT add a space between ISO codes and amounts (e.g., "CNY1000.00" not "CNY 1,000.00").
type Date ¶
Date represents a calendar date. Uses Go's time.Time internally for proper date handling (leap years, etc.).
func NewDate ¶
NewDate creates a Date from year, month, and day. If year is 0, uses the current year.
func NewDateFromTime ¶
NewDateFromTime creates a Date from a time.Time value.
func (*Date) DaysBetween ¶
DaysBetween returns the number of days from other to this date (d - other).
func (*Date) ShortString ¶
ShortString returns a shorter date format
type Duration ¶
type Duration struct {
Value decimal.Decimal
Unit string // "days", "hours", "minutes", "seconds", "weeks", "months", "years"
}
Duration represents a time duration with a specific unit. Supports: days, hours, minutes, seconds, weeks, months, years.
func NewDuration ¶
NewDuration creates a new Duration with the given value and unit.
func NewDurationFromString ¶
NewDurationFromString creates a Duration from string value and unit.
type Fraction ¶ added in v1.8.2
type Fraction struct {
Value *big.Rat
IsNapkin bool // true if this value was rounded by "as napkin"
Unit string // empty for dimensionless fractions
}
Fraction represents an exact rational number using Go's math/big.Rat. Fractions are always stored in lowest terms (big.Rat normalizes automatically).
func NewFraction ¶ added in v1.8.2
NewFraction creates a new Fraction from numerator and denominator. Returns an error if denominator is zero. The fraction is automatically reduced to lowest terms by big.Rat.
func NewFractionFromRat ¶ added in v1.8.2
NewFractionFromRat creates a Fraction from an existing big.Rat.
func (*Fraction) Denom ¶ added in v1.8.2
Denom returns the denominator of the fraction (after GCD reduction).
func (*Fraction) ExceedsComputationLimit ¶ added in v1.8.2
ExceedsComputationLimit returns true if the denominator exceeds 10^9 after GCD reduction, or if |numerator| exceeds 10^18 (int64 safety).
func (*Fraction) Num ¶ added in v1.8.2
Num returns the numerator of the fraction (after GCD reduction).
func (*Fraction) String ¶ added in v1.8.2
String returns the display representation of the fraction. Rules:
- denominator == 1 → integer
- denominator > 1000 → decimal fallback
- |numerator| > denominator → mixed number (e.g., "2 1/3")
- else → simple fraction (e.g., "2/3")
- IsNapkin → prefix "~"
- Unit → append " cup" etc.
type FunctionSpec ¶ added in v1.8.13
type FunctionSpec struct {
Name string // Function name
Params []ParamSpec // Parameter specifications
}
FunctionSpec describes a function's type signature for semantic analysis.
func GetFunctionSpec ¶ added in v1.8.13
func GetFunctionSpec(name string) *FunctionSpec
GetFunctionSpec returns the type specification for a function by name. Returns nil if the function is not found.
func (*FunctionSpec) GetParamAtIndex ¶ added in v1.8.13
func (f *FunctionSpec) GetParamAtIndex(index int) *ParamSpec
GetParamAtIndex returns the parameter spec for the given argument position. Handles variadic parameters (last param applies to all subsequent args).
type Number ¶
type Number struct {
Value decimal.Decimal
IsNapkin bool // true when produced by `as napkin` conversion
}
Number represents an arbitrary-precision decimal number. It uses the shopspring/decimal package for accurate decimal arithmetic.
func NewNumberFromString ¶
NewNumberFromString creates a Number from a string representation. Returns an error if the string cannot be parsed as a valid number.
type ParamSpec ¶ added in v1.8.13
type ParamSpec struct {
Name string // Parameter name (e.g., "rate", "duration")
Type ArgType // Expected argument type
Optional bool // True if parameter has a default value
Variadic bool // True if parameter accepts multiple values
Examples []string // Example values showing how to create this type
}
ParamSpec describes a function parameter with type constraints and examples.
type Percentage ¶ added in v1.7.0
Percentage represents a percentage value. The Value field stores the fractional form (e.g., 0.32 for 32%). Percentage preserves its identity through variables and applies widening on + and - operators: value + pct = value * (1 + pct).
func NewPercentage ¶ added in v1.7.0
func NewPercentage(value decimal.Decimal) *Percentage
NewPercentage creates a Percentage from a fractional decimal value. For 32%, pass 0.32.
func (*Percentage) String ¶ added in v1.7.0
func (p *Percentage) String() string
String returns the percentage in human-readable form (e.g., "32%").
type Quantity ¶
type Quantity struct {
Value decimal.Decimal
Unit string
IsNapkin bool // True if this is a napkin estimate (approximate value)
IsExplicit bool // True if unit was explicitly chosen via `in`/`as` conversion
IsPrecise bool // True if full precision requested via `as precise`
}
Quantity represents a value with a physical unit. This is a stub for future implementation with full unit support. For now, it simply stores the value and unit string.
func NewQuantity ¶
NewQuantity creates a new Quantity with the given value and unit.
func NewQuantityFromString ¶
NewQuantityFromString creates a Quantity from a string value and unit.
type Rate ¶
type Rate struct {
// Amount is the numerator (quantity per time unit)
// Can be any Quantity type (GB, requests, dollars, etc.)
Amount *Quantity
// PerUnit is the time unit denominator
// Valid units: "second", "minute", "hour", "day", "week", "month", "year"
PerUnit string
}
Rate represents a rate type: quantity per time period. Examples: 100 MB/s, $0.10/hour, 5 GB/day, 60 meters per second
Rate syntax:
- Slash (no spaces): "100 MB/s", "5 GB/day"
- Word "per" (with spaces): "100 MB per second", "5 GB per day"
Rates are first-class types that enable:
- Accumulation: rate * time = quantity
- Conversion: rate in different time units
- Arithmetic: adding/subtracting compatible rates
func (*Rate) CompoundUnit ¶
CompoundUnit returns the compound unit string for this rate (e.g., "MB/s", "USD/h"). The numerator uses the amount's unit and the denominator uses the abbreviated time unit.
func (*Rate) IsCompatible ¶
IsCompatible checks if two rates can be added/subtracted. Rates are compatible if their amounts have compatible units and same time periods.
type Time ¶
Time represents a time of day with optional timezone offset. Uses Go's time.Time internally.
func NewTime ¶
NewTime creates a Time from hour, minute, second (optional), and UTC offset (optional). hour: 0-23 for 24-hour format, or 1-12 for 12-hour with isPM minute: 0-59 second: 0-59 (use -1 if not specified) isPM: true for PM in 12-hour format, false for AM or 24-hour format utcOffsetMinutes: offset from UTC in minutes (0 for UTC/local time)
type Type ¶
type Type interface {
// String returns a human-readable representation of the value.
// This is used for display purposes and debugging.
String() string
}
Type is the interface that all CalcMark value types implement. All types can be converted to a human-readable string representation.