mirror of
https://github.com/nabbar/golib.git
synced 2025-12-24 11:51:02 +08:00
[root] - UPDATE documentation: enhanced README and TESTING guidelines - UPDATE dependencies: bump dependencies [config/components] - UPDATE mail component: apply update following changes in related package - UPDATE smtp component: apply update following changes in related package [mail] - MAJOR REFACTORING - REFACTOR package structure: reorganized into 4 specialized subpackages (queuer, render, sender, smtp) - ADD mail/queuer: mail queue management with counter, monitoring, and comprehensive tests - ADD mail/render: email template rendering with themes and direction handling (moved from mailer package) - ADD mail/sender: email composition and sending with attachments, priorities, and encoding - ADD mail/smtp: SMTP protocol handling with TLS modes and DSN support - ADD documentation: comprehensive README and TESTING for all subpackages - ADD tests: complete test suites with benchmarks, concurrency, and edge cases for all subpackages [mailer] - DEPRECATED - DELETE package: entire package merged into mail/render [mailPooler] - DEPRECATED - DELETE package: entire package merged into mail/queuer [smtp] - DEPRECATED - DELETE root package: entire package moved to mail/smtp - REFACTOR tlsmode: enhanced with encoding, formatting, and viper support (moved to mail/smtp/tlsmode) [size] - ADD documentation: comprehensive README - UPDATE interface: improved Size type methods - UPDATE encoding: enhanced marshaling support - UPDATE formatting: better unit handling and display - UPDATE parsing: improved error handling and validation [socket/server/unix] - ADD platform support: macOS-specific permission handling (perm_darwin.go) - ADD platform support: Linux-specific permission handling (perm_linux.go) - UPDATE listener: improved Unix socket and datagram listeners - UPDATE error handling: enhanced error messages for Unix sockets [socket/server/unixgram] - ADD platform support: macOS-specific permission handling (perm_darwin.go) - ADD platform support: Linux-specific permission handling (perm_linux.go) - UPDATE listener: improved Unix datagram listener - UPDATE error handling: enhanced error messages [socket/server/tcp] - UPDATE listener: improved TCP listener implementation
272 lines
8.1 KiB
Go
272 lines
8.1 KiB
Go
/***********************************************************************************************************************
|
|
*
|
|
* MIT License
|
|
*
|
|
* Copyright (c) 2022 Nicolas JUHEL
|
|
*
|
|
* 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.
|
|
*
|
|
*
|
|
**********************************************************************************************************************/
|
|
|
|
// Package size provides types and utilities for handling human-readable size representations.
|
|
//
|
|
// This package implements the Size type which represents a size in bytes and provides
|
|
// convenient methods for parsing, formatting, and manipulating size values. It supports
|
|
// binary unit prefixes (KiB, MiB, GiB, etc.) using powers of 1024.
|
|
//
|
|
// The Size type can be marshaled and unmarshaled to/from various formats including JSON,
|
|
// YAML, TOML, CBOR, and plain text. It also integrates with Viper for configuration management.
|
|
//
|
|
// # Basic Usage
|
|
//
|
|
// Parse a size string:
|
|
//
|
|
// size, err := size.Parse("10MB")
|
|
// if err != nil {
|
|
// log.Fatal(err)
|
|
// }
|
|
//
|
|
// Format a size:
|
|
//
|
|
// size := size.ParseUint64(1048576)
|
|
// fmt.Println(size.String()) // Output: "1.00 MB"
|
|
//
|
|
// Arithmetic operations:
|
|
//
|
|
// size := size.ParseUint64(1024)
|
|
// size.Mul(2.0) // Multiply by 2
|
|
// size.Add(512) // Add 512 bytes
|
|
//
|
|
// # Units
|
|
//
|
|
// The package supports the following binary units (powers of 1024):
|
|
// - B (Byte) = 1
|
|
// - KB (Kilobyte) = 1024
|
|
// - MB (Megabyte) = 1024²
|
|
// - GB (Gigabyte) = 1024³
|
|
// - TB (Terabyte) = 1024⁴
|
|
// - PB (Petabyte) = 1024⁵
|
|
// - EB (Exabyte) = 1024⁶
|
|
//
|
|
// # Thread Safety
|
|
//
|
|
// The Size type is a simple uint64 wrapper and is safe to copy by value.
|
|
// Methods that modify the Size value use pointer receivers.
|
|
//
|
|
// # See Also
|
|
//
|
|
// For handling durations in a similar manner, see:
|
|
// - github.com/nabbar/golib/duration
|
|
// - github.com/nabbar/golib/duration/big (for durations requiring arbitrary precision)
|
|
package size
|
|
|
|
import "math"
|
|
|
|
// Size represents a size in bytes.
|
|
//
|
|
// The Size type is a uint64 wrapper that provides convenient methods for parsing,
|
|
// formatting, and manipulating size values. All arithmetic operations protect against
|
|
// overflow and underflow.
|
|
//
|
|
// Example:
|
|
//
|
|
// size := size.ParseUint64(1048576) // 1 MB
|
|
// fmt.Println(size.String()) // Output: "1.00 MB"
|
|
// fmt.Println(size.MegaBytes()) // Output: 1
|
|
type Size uint64
|
|
|
|
const (
|
|
// SizeNul represents zero bytes.
|
|
SizeNul Size = 0
|
|
|
|
// SizeUnit represents one byte (1 B).
|
|
SizeUnit Size = 1
|
|
|
|
// SizeKilo represents one kilobyte (1 KB = 1024 bytes).
|
|
SizeKilo Size = 1 << 10
|
|
|
|
// SizeMega represents one megabyte (1 MB = 1024² bytes).
|
|
SizeMega Size = 1 << 20
|
|
|
|
// SizeGiga represents one gigabyte (1 GB = 1024³ bytes).
|
|
SizeGiga Size = 1 << 30
|
|
|
|
// SizeTera represents one terabyte (1 TB = 1024⁴ bytes).
|
|
SizeTera Size = 1 << 40
|
|
|
|
// SizePeta represents one petabyte (1 PB = 1024⁵ bytes).
|
|
SizePeta Size = 1 << 50
|
|
|
|
// SizeExa represents one exabyte (1 EB = 1024⁶ bytes).
|
|
SizeExa Size = 1 << 60
|
|
)
|
|
|
|
// defUnit is the default unit character used when formatting size values.
|
|
// It can be changed using SetDefaultUnit.
|
|
var defUnit = 'B'
|
|
|
|
// SetDefaultUnit sets the default unit character used when formatting size values.
|
|
//
|
|
// The unit parameter should be a single character (e.g., 'B' for Byte, 'o' for octet).
|
|
// If unit is 0 or an empty string, it defaults to 'B'.
|
|
//
|
|
// Example:
|
|
//
|
|
// size.SetDefaultUnit('o') // Use 'o' (octet) instead of 'B'
|
|
// size := size.ParseUint64(1024)
|
|
// fmt.Println(size.Unit(0)) // Output: "Ko" instead of "KB"
|
|
func SetDefaultUnit(unit rune) {
|
|
if unit == 0 {
|
|
defUnit = 'B'
|
|
} else if s := string(unit); len(s) < 1 {
|
|
defUnit = 'B'
|
|
} else {
|
|
defUnit = unit
|
|
}
|
|
}
|
|
|
|
// Parse parses a size string into a Size value.
|
|
//
|
|
// The size string is of the form "<number><unit>", where "<number>" is a
|
|
// decimal number and "<unit>" is one of the following:
|
|
// - "B" for byte
|
|
// - "K" for kilobyte
|
|
// - "M" for megabyte
|
|
// - "G" for gigabyte
|
|
// - "T" for terabyte
|
|
// - "P" for petabyte
|
|
// - "E" for exabyte
|
|
//
|
|
// Examples:
|
|
// - "1B" for 1 byte
|
|
// - "2K" for 2 kilobytes
|
|
// - "3M" for 3 megabytes
|
|
// - "4G" for 4 gigabytes
|
|
// - "5T" for 5 terabytes
|
|
// - "6P" for 6 petabytes
|
|
// - "7E" for 7 exabytes
|
|
//
|
|
// The function returns an error if the size string is invalid.
|
|
func Parse(s string) (Size, error) {
|
|
return parseString(s)
|
|
}
|
|
|
|
// ParseByte parses a byte slice into a Size value.
|
|
//
|
|
// The function is a simple wrapper around ParseBytes.
|
|
//
|
|
// Examples:
|
|
// - ParseByte([]byte("1B")) for 1 byte
|
|
// - ParseByte([]byte("2K")) for 2 kilobytes
|
|
// - ParseByte([]byte("3M")) for 3 megabytes
|
|
// - ParseByte([]byte("4G")) for 4 gigabytes
|
|
// - ParseByte([]byte("5T")) for 5 terabytes
|
|
// - ParseByte([]byte("6P")) for 6 petabytes
|
|
// - ParseByte([]byte("7E")) for 7 exabytes
|
|
//
|
|
// The function returns an error if the size string is invalid.
|
|
func ParseByte(p []byte) (Size, error) {
|
|
return parseBytes(p)
|
|
}
|
|
|
|
// ParseUint64 converts a uint64 value into a Size value.
|
|
//
|
|
// This is the most efficient way to create a Size from a known byte count.
|
|
//
|
|
// Example:
|
|
//
|
|
// size := size.ParseUint64(1048576) // 1 MB
|
|
// fmt.Println(size.MegaBytes()) // Output: 1
|
|
func ParseUint64(s uint64) Size {
|
|
return Size(s)
|
|
}
|
|
|
|
// ParseInt64 converts an int64 value into a Size value.
|
|
// The function will always return a positive Size value.
|
|
//
|
|
// Examples:
|
|
// - ParseInt64(-1)) for -1 byte but will return 1 byte
|
|
// - ParseInt64(1)) for 1 byte
|
|
// - ParseInt64(-1024)) for -1024 bytes but will return 1024 byte
|
|
// - ParseInt64(1024)) for 1024 bytes
|
|
func ParseInt64(s int64) Size {
|
|
if s < 0 {
|
|
return Size(uint64(-s))
|
|
} else {
|
|
return Size(uint64(s))
|
|
}
|
|
}
|
|
|
|
// ParseFloat64 converts a float64 value into a Size value.
|
|
// The function will always return a positive Size value.
|
|
//
|
|
// Examples:
|
|
// - ParseFloat64(-1.0)) for -1.0 bytes but will return 1 byte
|
|
// - ParseFloat64(1.0)) for 1.0 bytes
|
|
// - ParseFloat64(-1024.0)) for -1024.0 bytes but will return 1024 bytes
|
|
// - ParseFloat64(1024.0)) for 1024.0 bytes
|
|
func ParseFloat64(s float64) Size {
|
|
s = math.Floor(s)
|
|
|
|
if s > math.MaxUint64 {
|
|
return Size(uint64(math.MaxUint64))
|
|
} else if -s > math.MaxUint64 {
|
|
return Size(uint64(math.MaxUint64))
|
|
} else if s > 0 {
|
|
return Size(uint64(s))
|
|
} else {
|
|
return Size(uint64(-s))
|
|
}
|
|
}
|
|
|
|
// GetSize parses a size string and returns a Size value and a boolean indicating success.
|
|
// Deprecated: see Parse
|
|
func GetSize(s string) (sizeBytes Size, success bool) {
|
|
if z, e := parseString(s); e != nil {
|
|
return SizeNul, false
|
|
} else {
|
|
return z, true
|
|
}
|
|
}
|
|
|
|
// SizeFromInt64 converts an int64 value into a Size value.
|
|
// Deprecated: see ParseInt64
|
|
func SizeFromInt64(val int64) Size {
|
|
return ParseInt64(val)
|
|
}
|
|
|
|
// SizeFromFloat64 converts a float64 value into a Size value.
|
|
// Deprecated: see ParseFloat64
|
|
func SizeFromFloat64(val float64) Size {
|
|
return ParseFloat64(val)
|
|
}
|
|
|
|
// ParseSize parses a size string into a Size value.
|
|
// Deprecated: see Parse
|
|
func ParseSize(s string) (Size, error) {
|
|
return Parse(s)
|
|
}
|
|
|
|
// ParseByteAsSize parses a byte slice into a Size value.
|
|
// Deprecated: see ParseByte
|
|
func ParseByteAsSize(p []byte) (Size, error) {
|
|
return ParseByte(p)
|
|
}
|