{"id":19674678,"url":"https://github.com/cloudwego/frugal","last_synced_at":"2025-05-16T09:03:57.221Z","repository":{"id":37370830,"uuid":"390354851","full_name":"cloudwego/frugal","owner":"cloudwego","description":"A very fast dynamic Thrift serializer \u0026 deserializer.","archived":false,"fork":false,"pushed_at":"2025-04-01T04:04:14.000Z","size":1286,"stargazers_count":124,"open_issues_count":1,"forks_count":21,"subscribers_count":15,"default_branch":"main","last_synced_at":"2025-04-12T04:49:39.660Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cloudwego.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-07-28T13:08:43.000Z","updated_at":"2025-04-04T03:55:50.000Z","dependencies_parsed_at":"2024-06-28T11:06:07.297Z","dependency_job_id":"3e1cc250-24d4-4005-85cb-616ce0dab557","html_url":"https://github.com/cloudwego/frugal","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudwego%2Ffrugal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudwego%2Ffrugal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudwego%2Ffrugal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudwego%2Ffrugal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cloudwego","download_url":"https://codeload.github.com/cloudwego/frugal/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254501556,"owners_count":22081528,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-11T17:19:20.609Z","updated_at":"2025-05-16T09:03:57.185Z","avatar_url":"https://github.com/cloudwego.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Frugal\n\nEnglish | [中文](README_cn.md)\n\nA very fast dynamic Thrift serializer \u0026 deserializer without generating code.\n\n## Features\n\n### Code Generation Free\n\nTraditional Thrift serializer and deserializer are based on generated code which is no longer needed since we can make use of struct field tags.\n\n### High Performance\n\nBased on the test cases in `frugal/tests`, Frugal's performance is 3 to 4 times better than Apache Thrift (TBinaryProtocol).\n\nThere may be variations between different test cases. Feel free to share your test cases with us.\n\n```text\ngo version go1.23.6 linux/amd64\n\ngoos: linux\ngoarch: amd64\npkg: github.com/cloudwego/frugal/tests\ncpu: Intel(R) Xeon(R) Gold 5118 CPU @ 2.30GHz\n\nMarshal_ApacheThrift/small-4         \t 3468714\t     346.1 ns/op\t1684.32 MB/s\t       0 B/op\t       0 allocs/op\nMarshal_ApacheThrift/medium-4        \t  128386\t      9343 ns/op\t1875.07 MB/s\t       0 B/op\t       0 allocs/op\nMarshal_ApacheThrift/large-4         \t    7208\t    164521 ns/op\t1845.68 MB/s\t     109 B/op\t       0 allocs/op\nMarshal_Frugal/small-4               \t13032746\t     92.45 ns/op\t6306.09 MB/s\t       0 B/op\t       0 allocs/op\nMarshal_Frugal/medium-4              \t  327564\t      3669 ns/op\t4774.38 MB/s\t       0 B/op\t       0 allocs/op\nMarshal_Frugal/large-4               \t   18751\t     64212 ns/op\t4728.90 MB/s\t       0 B/op\t       0 allocs/op\n\nUnmarshal_ApacheThrift/small-4       \t 1548732\t     774.1 ns/op\t 753.15 MB/s\t    1120 B/op\t       4 allocs/op\nUnmarshal_ApacheThrift/medium-4      \t   42676\t     30665 ns/op\t 571.27 MB/s\t   44704 B/op\t     175 allocs/op\nUnmarshal_ApacheThrift/large-4       \t    2106\t    515642 ns/op\t 588.88 MB/s\t  775936 B/op\t    3030 allocs/op\nUnmarshal_Frugal/small-4             \t 4963635\t     266.2 ns/op\t2189.92 MB/s\t     544 B/op\t       1 allocs/op\nUnmarshal_Frugal/medium-4            \t   99786\t     11321 ns/op\t1547.45 MB/s\t   19908 B/op\t      57 allocs/op\nUnmarshal_Frugal/large-4             \t    5838\t    197987 ns/op\t1533.69 MB/s\t  349252 B/op\t     997 allocs/op\n```\n\n## What can you do with Frugal ?\n\n### Use Frugal as [Kitex](https://github.com/cloudwego/kitex) serializer and deserializer\n\nNo more massive serialization and deserialization code, leads to a more tidy project. No more meaningless diff of generated code in code review.\n\n### Serialized and Deserialize struct generated by [Thriftgo](https://github.com/cloudwego/thriftgo)\n\nIf you have a Thrift file, and all you need is using Frugal to do serialization and deserialization. You can use thriftgo to generate Go struct, then you can use Frugal.\n\n### Serialization and deserialization on a customized Go struct\n\nIf you don't want any Thrift files, and you want serialize or deserialize a customized Go struct. You can add some struct field tag to the Go struct, then you can use Frugal.\n\n## Usage\n\n### Using with Kitex\n\n#### 1. Update Kitex to v0.4.2 or higher version\n\n```shell\ngo get github.com/cloudwego/kitex@latest\n```\n\n#### 2. Generate code with `-thrift frugal_tag` option\n\nExample:\n\n```shell\nkitex -thrift frugal_tag -service a.b.c my.thrift\n```\n\nIf you don't need codec code, you can use `-thrift template=slim` option.\n\n```shell\nkitex -thrift frugal_tag,template=slim -service a.b.c my.thrift\n```\n\n#### 3. Init clients and servers with `WithPayloadCodec(thrift.NewThriftFrugalCodec())` option\n\nClient example:\n\n```go\npackage client\n\nimport (\n    \"context\"\n\n    \"example.com/kitex_test/client/kitex_gen/a/b/c/echo\"\n    \"github.com/cloudwego/kitex/client\"\n    \"github.com/cloudwego/kitex/pkg/remote/codec/thrift\"\n)\n\nfunc Echo() {\n    code := thrift.NewThriftCodecWithConfig(thrift.FastRead | thrift.FastWrite | thrift.FrugalRead | thrift.FrugalWrite)\n    cli := echo.MustNewClient(\"a.b.c\", client.WithPayloadCodec(codec))\n    ...\n}\n```\n\nServer example:\n\n```go\npackage main\n\nimport (\n    \"log\"\n\n    \"github.com/cloudwego/kitex/server\"\n    c \"example.com/kitex_test/kitex_gen/a/b/c/echo\"\n    \"github.com/cloudwego/kitex/pkg/remote/codec/thrift\"\n)\n\nfunc main() {\n    code := thrift.NewThriftCodecWithConfig(thrift.FastRead | thrift.FastWrite | thrift.FrugalRead | thrift.FrugalWrite)\n    svr := c.NewServer(new(EchoImpl), server.WithPayloadCodec(code))\n\n    err := svr.Run()\n    if err != nil {\n        log.Println(err.Error())\n    }\n}\n```\n\n### Using with Thrift IDL\n\n#### Prepare Thrift file\n\nWe can define a struct in Thrift file like below:\n\nmy.thrift:\n\n```thrift\nstruct MyStruct {\n    1: string msg\n    2: i64 code\n}\n```\n\n#### Use Thriftgo to generate code\n\nNow we have thrift file, we can use Thriftgo with `frugal_tag` option to generate Go code.\n\nExample:\n\n```shell\nthriftgo -r -o thrift -g go:frugal_tag,package_prefix=example.com/kitex_test/thrift my.thrift\n```\n\nIf you don't need codec code, you can use `template=slim` option\n\n```shell\nthriftgo -r -o thrift -g go:frugal_tag,template=slim,package_prefix=example.com/kitex_test/thrift my.thrift\n```\n\n#### Use Frugal to serialize or deserialize\n\nNow we can use Frugal to serialize or deserialize the struct defined in thrift file.\n\nExample:\n\n```go\npackage main\n\nimport (\n    \"github.com/cloudwego/frugal\"\n\n    \"example.com/kitex_test/thrift\"\n)\n\nfunc main() {\n    ms := \u0026thrift.MyStruct{\n        Msg: \"my message\",\n        Code: 1024,\n    }\n    ...\n    buf := make([]byte, frugal.EncodedSize(ms))\n    frugal.EncodeObject(buf, nil, ms)\n    ...\n    got := \u0026thrift.MyStruct{}\n    frugal.DecodeObject(buf, got)\n    ...\n}\n```\n\n### Serialization and deserialization on a customized Go struct\n\n#### Define a Go struct\n\nWe can define a struct like this:\n\n```go\ntype MyStruct struct {\n    Msg     string\n    Code    int64\n    Numbers []int64 \n}\n```\n\n#### Add Frugal tag to struct fields\n\nFrugal tag is like `frugal:\"1,default,string\"`, `1` is field ID, `default` is field requiredness, `string` is field type. Field ID and requiredness is always required, but field type is only required for `list`, `set` and `enum`.\n\nYou can add Frugal tag to `MyStruct` like below:\n\n```go\ntype MyStruct struct {\n    Msg     string  `frugal:\"1,default\"`\n    Code    int64   `frugal:\"2,default\"`\n    Numbers []int64 `frugal:\"3,default,list\u003ci64\u003e\"`\n}\n```\n\nAll types example:\n\n```go\ntype MyEnum int64\n\ntype Example struct {\n MyOptBool         *bool            `frugal:\"1,optional\"`\n MyReqBool         bool             `frugal:\"2,required\"`\n MyOptByte         *int8            `frugal:\"3,optional\"`\n MyReqByte         int8             `frugal:\"4,required\"`\n MyOptI16          *int16           `frugal:\"5,optional\"`\n MyReqI16          int16            `frugal:\"6,required\"`\n MyOptI32          *int32           `frugal:\"7,optional\"`\n MyReqI32          int32            `frugal:\"8,required\"`\n MyOptI64          *int64           `frugal:\"9,optional\"`\n MyReqI64          int64            `frugal:\"10,required\"`\n MyOptString       *string          `frugal:\"11,optional\"`\n MyReqString       string           `frugal:\"12,required\"`\n MyOptBinary       []byte           `frugal:\"13,optional\"`\n MyReqBinary       []byte           `frugal:\"14,required\"`\n MyOptI64Set       []int64          `frugal:\"15,optional,set\u003ci64\u003e\"`\n MyReqI64Set       []int64          `frugal:\"16,required,set\u003ci64\u003e\"`\n MyOptI64List      []int64          `frugal:\"17,optional,list\u003ci64\u003e\"`\n MyReqI64List      []int64          `frugal:\"18,required,list\u003ci64\u003e\"`\n MyOptI64StringMap map[int64]string `frugal:\"19,optional\"`\n MyReqI64StringMap map[int64]string `frugal:\"20,required\"`\n MyOptEnum         *MyEnum          `frugal:\"21,optional,i64\"`\n MyReqEnum         *MyEnum          `frugal:\"22,optional,i64\"`\n}\n```\n\n#### Use Frugal to serialize or deserialize\n\nExample:\n\n```go\npackage main\n\nimport (\n    \"github.com/cloudwego/frugal\"\n)\n\nfunc main() {\n    ms := \u0026thrift.MyStruct{\n        Msg: \"my message\",\n        Code: 1024,\n        Numbers: []int64{0, 1, 2, 3, 4},\n    }\n    ...\n    buf := make([]byte, frugal.EncodedSize(ms))\n    frugal.EncodeObject(buf, nil, ms)\n    ...\n    got := \u0026thrift.MyStruct{}\n    frugal.DecodeObject(buf, got)\n    ...\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudwego%2Ffrugal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcloudwego%2Ffrugal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudwego%2Ffrugal/lists"}