A super-simple, very fast data file format!
Go to file
2025-04-18 12:29:35 -05:00
bench Fin rebrand 2025-04-18 12:12:49 -05:00
tests Fin rebrand 2025-04-18 12:12:49 -05:00
.gitignore Initial commit 2025-02-16 21:09:54 -06:00
config.go add copyright to source 2025-04-18 12:27:13 -05:00
go.mod Fin rebrand 2025-04-18 12:12:49 -05:00
go.sum Update package name to SCF 2025-03-05 09:14:20 -06:00
LICENSE.md Switch license to md 2025-04-18 12:24:20 -05:00
pool.go add copyright to source 2025-04-18 12:27:13 -05:00
README.md readme 2025-04-18 12:29:35 -05:00
scanner.go add copyright to source 2025-04-18 12:27:13 -05:00
token.go add copyright to source 2025-04-18 12:27:13 -05:00

Fin

Fin is a very light, very intuitive config file format! Few symbols, few rules, quite flexible. Has support for comments, arrays, maps, and type guarantees.

Mercilessly benchmarked, fully tested. Fin competes toe-to-toe with Go's native JSON library, and handily outperforms the reference TOML and YAML implementations.

Format

Fin has very very simple syntax.

-- Lua style comments!
host  "localhost"
port  8080        -- no = for assignment!
debug true

allowed_ips {
    "192.168.1.1"
    "192.168.1.2"
    "10.0.0.1"
}

--[[
    Feel free to space out your explanations!

    All is well and good.
]]
database {
    host "db.example.com"
    port 5432
    credentials {
        username "admin"
        password "secure123"
    }
}

Installation

go get git.sharkk.net/Sharkk/Fin

Usage

Basic Usage

package main

import (
    "fmt"
    "os"

    "git.sharkk.net/Sharkk/Fin"
)

func main() {
    file, err := os.Open("config.conf")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    // Pass a string to be loaded by the parser!
    cfg, err := fin.Load(file)
    if err != nil {
        panic(err)
    }

    // Access values with type conversion.
    host, err := cfg.GetString("database.host")
    port, err := cfg.GetInt("database.port")
    debug, err := cfg.GetBool("debug")

    // Use default values for missing keys
    timeout := cfg.GetOr("timeout", 30).(int)

    // Get the entire map to traverse directly (cuts traversal time by 50%!)
    entireMap := cfg.GetData()
    other, err := entireMap["database"]["host"].(string)
}

Type Conversion

The parser automatically converts values to appropriate types:

boolValue, err   := cfg.GetBool("feature.enabled")
intValue, err    := cfg.GetInt("server.port")
floatValue, err  := cfg.GetFloat("threshold")
stringValue, err := cfg.GetString("app.name")
arrayValue, err  := cfg.GetArray("allowed_ips")
mapValue, err    := cfg.GetMap("database")

// Generic getter (returns any)
value, err := cfg.Get("some.key")

Accessing Arrays and Maps

Access array elements and nested map values using dot notation:

// Access the first element in the array
firstIP, err := cfg.GetString("allowed_ips.0")

// Access deeply nested values
username, err := cfg.GetString("database.credentials.username")

Performance

Fin goes blow-for-blow against Go's standard JSON library, and performs incredibly versus the standard TOML and YAML implementations:

Benchmark Operations Time (ns/op) Memory (B/op) Allocations (allocs/op)
Small Config Files
Fin 1,000,000 1,052 1,743 15
JSON 1,000,000 1,112 1,384 23
YAML 215,121 5,600 8,888 82
TOML 286,334 4,483 4,520 67
Medium Config Files
Fin 211,863 5,696 4,056 74
JSON 261,925 4,602 5,344 89
YAML 50,010 23,965 21,577 347
TOML 68,420 17,639 16,348 208
Large Config Files
Fin 55,338 21,556 12,208 207
JSON 70,219 17,202 18,140 297
YAML 12,536 95,945 65,568 1,208
TOML 14,732 74,198 66,050 669

AMD Ryzen 9 7950X

Why Choose Fin?

  • Readability: Simple syntax that's easy for humans to read and write
  • Flexibility: Supports various data types and nested structures
  • Performance: Fast parsing with minimal overhead
  • Type Safety: Strong typing with automatic conversion
  • Simplicity: No external dependencies required

License

(Sharkk Minimal License)[LICENSE]