go-unic is a reliable, highβperformance Go library for parsing, serialising, and working with configuration files in the Universal Configuration Format (UNIC). UNIC combines readability, a minimalistic syntax, and flexibility β letting you describe complex data structures as easily as with JSON or YAML, but with a syntax that feels more natural for humans.
- Features
- Installation
- Quick Start
- UNIC Syntax
- Struct Tags (options)
- Examples
- Comparison with other formats
- Contributing
- License
- Humanβreadable syntax β intuitive, without superfluous symbols (like Nginx or HCL).
- Support for all major Go types: structs, slices, maps, scalars (numbers, strings, booleans).
- Flexible tagβbased control β set field names, default values, omit empty fields, attributes, comments.
- Structure merging β automatically combine fields when serialising multiple objects with the same key.
- Arbitrary nesting depth β blocks, lists, and maps can be combined freely.
- Support for
anyinterfaces β deserialise intomap[string]anyor[]anywhen needed. - High performance β minimal reflection usage, cached struct metadata.
- Zero allocations during parsing (uses a
bbbuffer).
go get -u go.osspkg.com/unic@latestTo convert UNIC data into a Go struct, use unic.Unmarshal:
package main
import (
"fmt"
"os"
"go.osspkg.com/unic"
)
type Config struct {
LogLevel int `unic:"log_level,default=1"`
Port int `unic:"port"`
Features []string `unic:"features,omitempty"`
}
func main() {
data, err := os.ReadFile("config.unic")
if err != nil {
fmt.Printf("Error reading file: %v\n", err)
return
}
var cfg Config
if err := unic.Unmarshal(data, &cfg); err != nil {
fmt.Printf("Parsing error: %v\n", err)
return
}
fmt.Printf("Configuration: log_level=%d, port=%d, features=%v\n",
cfg.LogLevel, cfg.Port, cfg.Features)
}To write a struct to UNIC format, use unic.Marshal:
package main
import (
"fmt"
"os"
"go.osspkg.com/unic"
)
func main() {
cfg := Config{
LogLevel: 2,
Port: 8080,
Features: []string{"auth", "metrics"},
}
data, err := unic.Marshal(cfg)
if err != nil {
fmt.Printf("Serialisation error: %v\n", err)
return
}
if err := os.WriteFile("config.unic", data, 0644); err != nil {
fmt.Printf("Write error: %v\n", err)
}
}UNIC is a text file containing fields, blocks, lists, and maps. Basic rules:
| Construct | Example | Description |
|---|---|---|
| Field | key value; |
Assigns a scalar value (string, number, boolean). |
| Block | key { field1 val1; field2 val2; } |
Groups fields (similar to a struct). |
| List | key [val1, val2, val3]; |
Ordered collection of values. |
| Map | key (key1, val1, key2, val2); |
Keyβvalue pairs (keys are always strings). |
| Attributes | key attr1 attr2 { ... } |
Values before an opening block brace become struct attributes. |
To avoid conflicts with system characters ({}[]();,#), spaces, quotes, or line breaks, the following rules apply:
- If the string contains
",{,},[,],(,),#,;,,or spaces β enclose it in single quotes:'hello "world"'. - If the string contains
',{,},[,],(,),#,;,,or spaces β enclose it in double quotes:"hello 'world'". - If the string contains both
'and"as well as special characters or line breaks β use triple backticks:```hello 'world' "foo"```.
Example:
message 'Hello, "friend"!';
path "C:\\Program Files\\App";
multiline ```first line
second line```;
- Singleβline β after
;on the same line:port 80; # standard port - Block β after
{on the same line (applies to the entire block):server { # server settings host '127.0.0.1'; }
If values are given before an opening block brace, they are interpreted as struct attributes. The attr=N tag sets the ordinal number (starting from 1).
Example:
server web 80 { host 'localhost'; }
corresponds to the struct:
package main
type Server struct {
Tag string `unic:"tag,attr=1"` // "web"
Port int `unic:"port,attr=2"` // 80
Host string `unic:"host"`
}The unic tag has the format: unic:"name[,option1='value'][,option2='value']..."
Available options:
| Option | Description |
|---|---|
name |
Field name in the configuration (mandatory). |
default |
Default value (for scalars or lists separated by ;). |
omitempty |
If the field is empty (zero value), it is omitted during serialisation and ignored on parse. |
attr |
Ordinal number of a block attribute (number > 0). |
desc |
Comment added during serialisation. |
Example:
package main
type Config struct {
LogLevel int `unic:"log_level,default=1,desc='log level'"`
Servers []Server `unic:"server"`
}
type Server struct {
Name string `unic:"name,attr=1"`
Port int `unic:"port"`
}Configuration:
log_level 1;
servers {
server web {
port 80;
host 'localhost';
}
server admin {
port 8080;
host '127.0.0.1';
auth (user1, passwd1, user2, passwd2);
}
}
Go struct:
package main
type Config struct {
LogLevel int `unic:"log_level"`
Servers struct {
Servers []struct {
Name string `unic:"name,attr=1"`
Port int `unic:"port"`
Host string `unic:"host"`
Auth map[string]string `unic:"auth,omitempty"`
} `unic:"server"`
} `unic:"servers"`
}unic.Marshal accepts several arguments β all are merged into one document. If fields with the same name appear in different structs, they are combined (merged) into a single block.
package main
type Part1 struct {
Common string `unic:"common"`
A int `unic:"a"`
}
type Part2 struct {
Common string `unic:"common"`
B bool `unic:"b"`
}
data, _ := unic.Marshal(Part1{Common:"shared", A:42}, Part2{Common:"shared", B:true})
// Output:
// common shared;
// a 42;
// b true;| Format | Readability | Complex structures | Comments | Performance (Go) |
|---|---|---|---|---|
| UNIC | β β β β β | β β β β β | β | High (reflection with cache) |
| JSON | β β β ββ | β β β β β | β | Very high |
| YAML | β β β β β | β β β β β | β | Medium |
| TOML | β β β β β | β β β ββ | β | Medium |
| HCL | β β β β β | β β β β β | β | Medium |
UNIC offers the best balance between readability and performance, especially if you need comments, attributes, and flexible struct merging.
We welcome your ideas and improvements! To contribute:
- Fork the repository.
- Create a branch for your feature (
git checkout -b feature/amazing-feature). - Make your changes and write tests.
- Ensure all linters and tests pass (
make pre-commit). - Open a pull request.
Distributed under the BSD 3βClause License. See the LICENSE file for details.