{"id":30126475,"url":"https://github.com/iotaledger/bcs-go","last_synced_at":"2025-08-10T16:50:24.200Z","repository":{"id":281068140,"uuid":"943828715","full_name":"iotaledger/bcs-go","owner":"iotaledger","description":"BCS encoding library for Golang","archived":false,"fork":false,"pushed_at":"2025-07-16T10:09:25.000Z","size":156,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-07-31T09:49:48.661Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/iotaledger.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-03-06T10:33:32.000Z","updated_at":"2025-07-16T10:09:29.000Z","dependencies_parsed_at":"2025-03-06T20:40:22.239Z","dependency_job_id":null,"html_url":"https://github.com/iotaledger/bcs-go","commit_stats":null,"previous_names":["iotaledger/bcs-go"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/iotaledger/bcs-go","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iotaledger%2Fbcs-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iotaledger%2Fbcs-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iotaledger%2Fbcs-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iotaledger%2Fbcs-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iotaledger","download_url":"https://codeload.github.com/iotaledger/bcs-go/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iotaledger%2Fbcs-go/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269756297,"owners_count":24470560,"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","status":"online","status_checked_at":"2025-08-10T02:00:08.965Z","response_time":71,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":"2025-08-10T16:50:19.866Z","updated_at":"2025-08-10T16:50:24.142Z","avatar_url":"https://github.com/iotaledger.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# BCS serialization\n\n## What can this library do\n\n* Serialize basic types: **bool**, **int8**, **int16**, **int32**, **int64**, **int**, **uint8**, **uint16**, **uint32**, **uint64**, **uint**, **string**.\n* Serialize extended types: **time.Time**, **big.Int**, **ULEB128** (variable-length int).\n* Recursively serialize complex types: **structures**, **arrays**, **slices** and **maps**.\n* Define **enumerations** in form of **interface** types or **struct** types.\n* Define **custom encoders/decoders** through functors or methods.\n* Define **custom initializer** to be executed after decoding.\n* Define **type parameters** using type's method or structure field tag.\n\n## Usage\n\n#### Marshaling/Unmarshaling\n\n###### Bytes:\n\n```\nv := \"hello\"\nvEncoded := bcs.MustMarshal(\u0026v)\nvDecoded := bcs.MustUnmarshal(vEncoded)\n```\n\n###### Stream:\n\n```\nv := \"hello\"\nvar wBuff bytes.Buffer\nbcs.MustMarshalStream(\u0026v, \u0026wBuff)\nvEncoded := wBuff.Bytes()\n\nrBuff := bytes.NewReader(vEncoded)\nvDecoded := bcs.MustUnmarshal(vEncoded)\n```\n\n###### Into existing value:\n\n```\n...\nvar vDecodedFromBytes string\nbcs.MustUnmarshalInto(vEncoded, \u0026vDecodedFromBytes)\n\n...\nvar vDecodedFromStream string\nbcs.MustUnmarshalStreamInto(ioStreamReader, \u0026vDecodedFromStream)\n```\n\n#### Using encoder/decoder\n\n```\nv1 := \"hello\"\nv2 := 123\nvar wBuff bytes.Buffer\nenc := bcs.NewEncoder(wBuff)\nenc.MustEncode(v1)\nenc.MustEncode(\u0026v2) // note both value and pointer supported\nencoded := wBuff.Bytes()\n\ndec := bcs.NewDecoder(bytes.NewReader(encoded))\ndec.MustDecode(\u0026v1)\ndec.MustDecode(\u0026v2)\n```\n\n**NOTE:** Althouth `Encode`() supports both value and pointer as argument, try prefering passing a pointer (see perf section)\n\n#### Using BytesEncoder/BytesDecoder\n\n```\nv1 := \"hello\"\nv2 := 123\nenc := bcs.NewBytesEncoder()\nenc.MustEncode(v1)\nenc.MustEncode(\u0026v2) // note both value and pointer supported\nencoded := enc.Bytes()\n\ndec := bcs.NewBytesDecoder(encoded)\ndec.MustDecode(\u0026v1)\ndec.MustDecode(\u0026v2)\n```\n\n#### Decoder with helper functions\n\n```\ndec := bcs.NewDecoder(bytes.NewReader(encoded))\nv1 := bcs.MustDecode[string](dec)\nv2 := bcs.MustDecode[int](dec)\n```\n\n#### Using specialized functions of encoder/decoder\n\n```\nvar wBuff bytes.Buffer\nenc := bcs.NewEncoder(wBuff)\nenc.WriteString(\"hello\") // will have better performance than enc.Encode()\nenc.WriteInt(123)\nif enc.Err() != nil {\n   return enc.Err()\n}\nencoded := wBuff.Bytes()\n\ndec := bcs.NewDecoder(bytes.NewReader(encoded))\nv1 := dec.ReadString()  // will have better performance than dec.Decode()\nv2 := dec.ReadInt()\nif dec.Err() != nil {\n   return enc.Err()\n}\n\n```\n\n#### Error handling\n\n###### Classic:\n\n```\nif err := bcs.Marshal(\u0026v); err != nil {\n   return err\n}\n```\n\n###### Deffered:\n\n```\ndec := bcs.NewDecoder(bytes.NewReader(encoded))\nv1 := bcs.Decode[string](dec) // will return empty value if error happen\nv2 := bcs.Decode[int](dec)    // if there was on error on previous line, this line will just do nothing and return empty value\n\nif err := dec.Err(); err != nil {\n   return err\n}\n```\n\n###### Panic:\n\n```\nv := bcs.MustUnmarshal[string](encoded)\n```\n\n###### Error checked automatically after MarshalBCS/UnmarshalBCS and custom serialization functions\n\n```\nfunc (p *MyStruct) MarshalBCS(e *bcs.Encoder) error {\n    e.Encode(\u0026p.Field1)\n    e.Encode(\u0026p.Field2) // if an error happened on previous line, this line will just do nothing\n    return nil // the encoder will automatically check if there was an error after call to MarshalBCS\n}\n```\n\n## Complex types\n\n#### Structures\n\nStructures are encoded/decoded same way as basic types. Fields are encoded in the order of their definition. Fields may have any encodable type, including nested structs and collections.\n\nOnly **public** **fields** of structure are serialized **by default**. To include **private fields** use  `bcs:\"export\"`.\n\nTo **exclude field** from serialization, use \\`bcs:\"-\"\\`.\n\n```\ntype TestStruct struct {\n   A int\n   B string\n   C []byte `bcs:\"-\"` // excluded\n   d bool   `bcs:\"export\"` // notice fiels is unexported, but we force it to be exported through BCS\n}\n\nv := TestStruct{10, \"hello\", true}\n\nvEncoded := bcs.MustMarshal(\u0026v)\n\n// This in equivalent to:\n// var wBuff bytes.Buffer\n// enc := bcs.NewEncoder(\u0026wBuff)\n// enc.WriteInt(v.A)\n// enc.WriteString(v.B)\n// enc.WriteString(v.d)\n```\n\n#### Arrays of constant length\n\nElements of array are written one by one. They could be of any encodable type (e.g. structs or collections):\n\n```\nvar v [3]int8 = {1, 2, 3}\nvEncoded := bcs.MustMarshal(\u0026v)\n// vEncoded = []byte{1, 2, 3}\n```\n\n**WARNING:** Avoid using construct `v[:]`, because it will result in array being treated as slice, so length will be encoded in addition to elements.\n\n#### Slices\n\n```\n// Slices are encoded same way as arrays except that they also have length encoded at start as variable-length int\nvar v []int8 = {1, 2, 3}\nvEncoded := bcs.MustMarshal(\u0026v)\n// vEncoded = []byte{3, 1, 2, 3}\n```\n\n#### Maps\n\nMaps are encoded as slice of key-value entries, ordered by byte representation of keys:\n\n```\nv := map[int8]int8{2: 10, 3: 5, 1: 20}\nvEncoded := bcs.MustMarshal(\u0026v)\n// vEncoded = []byte{3, 1, 20, 2, 10, 3, 5}\n```\n\n#### Strings\n\nStrings encoded as byte slices:\n\n```\nv := \"abc\"\nvEncoded := bcs.MustMarshal(\u0026v)\n// vEncoded = []byte{0x3, 0x61, 0x62, 0x63}\n```\n\n## Pointers\n\nUpon encoding pointers are **dereferenced**. Pointer value **must** be either **non-nil** or marked as **optional** (see other sections). Otherwise encoding will fail with error.\n\nUpon decoding, for each **nil** pointer new value is **allocated** and assigned. If pointer field was preset before decoding with non-nil value, the **preset** value is **kept**.\n\n```\ntype testStruct struct {\n\tA **bool\n}\n\na := true\npa := \u0026a\nv := \u0026testStruct{A: \u0026pa}\npv := \u0026v\n\nvEnc := bcs.MustMarshal(\u0026pv)\nvDec := bcs.MustUnmarshal[****testStruct](vEnc)\nrequire.Equal(t, v, ***vDec)\n```\n\n## Interfaces\n\nInterface can be serialized in three different ways:\n\n* **By default**, interface is encoded just as plain value. For decoding it **must** contain some value to specify an actual type.\n* If interface is registered as **enumeration** (see sections below), the library uses its registered enum specification for serialization. In that case, no need to preset value on decoding.\n* If structure's interface field is marked as **\"not_enum\"** (see sections below), the library ignores enum registration for that field.\n* If interface has custom serialization **functor**, that functor is used for serialization and everything else is ignored.\n\nIf interface does not satisfy any of those criterias, serialization will return an **error**.\n\n###### Encoding enum interface's value using Marshal/Encode\n\nIf you need to encode the value wrapped by the interface, which is registered as enum, you can pass interface **by value** to `Encode()` of `bcs.Encoder`:\n\n```\ntype Message interface{}\n\nvar m Message = \"hello\"\ne := bcs.NewBytesEncoder()\ne.Encode(m)\n```\n\nThis works, because `Encode()` function has argument of type `any`, so information about `Message` interface is lost - value in unpacked from `Message` and packed as `any`.\n\nWith `bcs.Marshal` this won't work, because it enforces pointer argument, so passing interface by value is not an option.\nFor that purpose, you can either cast interface to actual value (`bcs.Marshal(m.(string)`). But if the type is unknown, you can cast to `any` and then take its pointer:\n\n```\n...\nvar eI any = m\nbcs.Marshal(\u0026eI)\n\n// Or:\n\nbcs.Marshal(lo.ToPtr[any](m))\n```\n\n## Enumerations\n\nBCS supports enumerations - values of variable type from the fixed list of types. It is implemented as enumeration variant index being encoded as variabl-length int before encoding the value.\nCurrent BCS library supports two different styles of defining enumerations: struct enums and interface enums.\n\n#### Struct enumerations\n\nStruct enumeration is defined by defining a structure.\nThe structure:\n\n* Must have all fields of nullable (e.g. pointer) and encodable types.\n* Must define method **IsBcsEnum** with **value receiver**.\n\n**One and only one** **fields** of that structure **must** be set when encoding.\nIndex of the field is used as index of enum variant.\n\n```\ntype TestEnum struct {\n   A *int16\n   B *string\n   C *bool\n}\n\nfunc (TestEnum) IsBcsEnum() {}\n\nvar a int16 = 10\nbcs.Marshal(\u0026TestEnum{A: \u0026a}) // []byte{0, 10, 0}\nb := \"abc\"\nbcs.Marshal(\u0026TestEnum{B: \u0026b}) // []byte{1, 0x3, 0x61, 0x62, 0x63}\nc := true\nbcs.Marshal(\u0026TestEnum{C: \u0026c}) // []byte{2, 1}\n```\n\n#### Interface enumerations\n\nHaving separate structure type for enumeration is sometimes not an elegant solution. So there is another way to define an enum - based on interface.\n\n* Enum type **must be an interface**. It can have methods.\n* All of the variant types must **implement** **the interface** (except for `bcs.None` - see below). If variant implements interface with **pointer receiver**, pointer to a type must be used as a variant type.\n* Variant type **cannot be an interface** type.\n* Enum must be **registered** using one of `bcs.RegisterEnum*(...)` functions.\n\n```\ntype TestEnum interface{}\n\nvar _ = bcs.RegisterEnumType3[TestEnum, int16, string, bool]\n\nvar v TestEnum = int16(10)\nbcs.Marshal(\u0026v) // []byte{0, 10, 0}\nv = \"abc\"\nbcs.Marshal(\u0026v) // []byte{1, 0x3, 0x61, 0x62, 0x63}\nv = true\nbcs.Marshal(\u0026v) // []byte{2, 1}\n```\n\n###### bcs.None\n\nFor absense of the value special type `bcs.None` can be used as variant.\nEncoding interface enum type with nil value will result in an error if enum does not have bcs.None registered as one of variants.\n\n```\n...\nvar _ = bcs.RegisterEnumType3[TestEnum, bcs.None, int16, string, bool]\n\nv = nil\nbcs.Marshal(\u0026v) // []byte{0}\n```\n\n###### Passing an interface to Encode\n\n**WARNING**: Methods `Encode()` of types `bcs.Encoder` expects encoded value to be passed through argument of type `any`. That type is an interface, which means that when passing enum interface to it the value will be unwrapped and wrapped again into `any` thus loosing the information about initial interface type.\nTo avoid that, pass it as pointer: `e.Encode(\u0026v)`. That way the information about original interface type is preserved.\nThere is no such issue with `bcs.Marshal` because its argument enforces pointer value.\n\n## Customization\n\n#### Customizing struct field\n\nEach struct field encoding/decoding can be customized using struct field tag metainformation.\nThere are three tags available:\n\n* **bcs** - customizes serialization of field value\n* **bcs_elem** - customizes serialization of array/slice elememt if field is array/slice.\n* **bcs_key / bcs_value** - customizes serialization of map key/value if field is a map.\n\nExample:\n\n```\ntype TestStruct struct {\n   I *int        `bcs:\"optional\"`\n   hidden bool   `bcs:\"export\"`\n   Excluded bool `bcs:\"-\"`\n   S []*int64    `bcs:\"len_bytes=4\" bcs_elem:\"compact\"`\n   M map[int]int `bcs:\"len_bytes=2\" bcs_key:\"type=int32\" bcs_value:\"bytearr\"`\n   F interface{} `bcs:\"not_enum\"`\n}\n```\n\nFor the list of available customizations see next sections.\n\n#### Customizing type\n\nMethod **BCSOptions()** can be defined to customize type serialization.\nNOTE: The method **must** have value receiver.\n\n```\ntype CompactInt int\n\nfunc (CompactInt) BCSOptions() bcs.TypeOptions {\n   return bcs.TypeOptions{IsCompactInt: true}\n}\n```\n\nIt can also be used to customize element/key/value serialization of arrays/slices/maps:\n\n```\ntype MapOfCompactInts map[string]int64\n\nfunc (MapOfCompactInts) BCSOptions() bcs.TypeOptions {\n   return bcs.TypeOptions{\n      MapValue: \u0026bcs.TypeOptions{\n         IsCompactInt: true,\n      },\n   }\n}\n```\n\n#### Manual serialization\n\nSerizalization of a type can fully customized by implementing custom encoder/decoder.\nCustom serialization can be provided **for** **any type:** basic types, structs, collections, pointers, third-part types etc.\n\nThere are multiple methods available in Encoder and Decoder to help implement manual serialization, including serialization of optionals, collections and enumerations (see sections below).\n\nNOTE: No need to manually check an **error** inside of custom serialization methods and functions - it will be checked automatically by the encoder/decoder after the call.\n\n###### MarshalBCS/UnmarshalBCS methods:\n\nOne or both methods of the following methods can be defined to implement manual serialization.\n\n* Encoding - **MarshalBCS**. Supports both **value receiver** and **pointer receiver**.\n* Decoding - **UnmarshalBCS**. It **must** have **pointer receiver**.\n\n```\ntype TestStruct struct {\n   A int\n   ...\n}\n\nfunc (s *TestStruct) MarshalBCS(e *bcs.Encoder) ([]byte, error) {\n   e.WriteInt(s.A)\n   ...   \n}\n\nfunc (s *TestStruct) UnmarshalBCS(d *bcs.Decoder) error {\n   s.A = d.ReadInt()\n   ...\n}\n```\n\n###### Read/Write methods:\n\nIn addition to MarshalBCS/UnmarshalBCS, another pair of methods is supported: **Read()** and **Write()**.\nThis is done to ensure compatibility with some others libraries.\n\n```\ntype TestStruct struct {\n   A int\n   ...\n}\n\nfunc (s *TestStruct) Write(w io.Writer) error {\n   e := bcs.NewEncoder(w)  \n   e.WriteInt(s.A)\n   ...\n}\n\nfunc (s *TestStruct) Read(r io.Reader) error {\n   d := bcs.NewDecoder(r)\n   e.A = d.ReadInt()\n   ...\n}\n\n```\n\n###### Custom serialization functors:\n\nSpecial functions can be registered to customize serialization of a type. This has two **advantages** over using methods:\n\n* Allows to implement custom serialization for **third-party types** (like it is implemented for **time.Time** and **big.Int**).\n* Allows to implement custom serialization for **interfaces**.\n\nIt is convenient (but not required) to run register them upon program initialization using Golang's package **init()** function.\nIt is permitted to register **separate functors** for the **type itself** and its **pointer type**.\n\n```\nfunc init() {\n   AddCustomEncoder(func(e *Encoder, v time.Time) error {\n      e.w.WriteInt64(v.UnixNano())\n      return e.w.Err\n   })\n\n   AddCustomDecoder(func(d *Decoder, v *time.Time) error {\n      *v = time.Unix(0, d.r.ReadInt64())\n      return d.r.Err\n   })\n}\n\n```\n\n#### Custom initialization\n\nType can have custom initializer function to be executed after the value is decoded.\nIt is implemented by defining **BCSInit** method. It **must** have **pointer receiver**.\n\nSerialization will **fail** if unexported field has BCS tag, but is not marked as \"export\". Reason: such case signals mixed intention.\nSerialization will also **fail** if already exported field has \"export\" tag. Reason: engineers might have a standard expectation, that when field is renamed it becomes hidden. But they may forget about BCS serialization.\n\n```\ntype TestStruct struct {\n   A int\n   B int `bcs:\"-\"`\n}\n\nfunc (s *TestStruct) BCSInit() error {\n\ts.B = s.A * 2\n}\n```\n\n#### Available field tags\n\n###### \"export\"\n\nMarks unexported field to be exported through BCS.\nAppicable to: **unexported fields of structrures**.\n\n```\ntype TestStruct struct {\n   unexportedField         int                   // This field won't be serialized because it is unexported\n   unexportedButSerialized string `bcs:\"export\"` // Although this field is unexported too, it will be serialized \n}\n```\n\n###### \"optional\"\n\nMarks field as optional.\nApplicable to: **pointers**, **interfaces, maps, slices**.\n\nWhen encoding such field, first presense flag is encoded as 1 byte, and then value itself is encoded if present.\n\n```\ntype TestStruct struct {\n   A *int16 `bcs:\"optional\"`\n}\n\nvar a int16 = 10\nwithValue    := bcs.MustMarshal(\u0026TestStruct{A: \u0026a})  // []byte{1, 10, 0}\nwithoutValue := bcs.MustMarshal(\u0026TestStruct{A: nil}) // []byte{0}\n```\n\n###### \"compact\"\n\nMark integer field to be written as **ULEB128** - variable-length integer which enhances space usage but decreases serialization performance. This is the same format used to serialize collection length or enumeration variant index.\nApplicable to: **integers**.\n\n**WARNING:** BCS specification does not have mentions about ULEB128 being used for anything other than length of collections and enumeration variant indexes. So this logic is a custom extension mostly designed for usage with types, which are not used for interaction with other actors.\n\n###### \"type=T\"\n\nAllows to **override type** of integer value. For example, if field has type int64, using this tag you can store it as int16.\nApplicable to: **integers**.\nPossible values of **T**: i8, i16, i32, i64, u8, u16, u32, u64 (and corresponding aliases int8, uint16, ...).\n\n```\ntype TestStruct struct {\n   A int64 `bcs:\"type=i16\"`\n}\n\nbcs.Marshal(\u0026TestStruct{A: 10}) // []byte{10, 0}\n```\n\n**WARNING:** In case of overflow an **error** is returned. This is done to ensure, that field is not accidentally missused when type from definition is bigger than serialized type.\n\n###### \"len_bytes=N\"\n\nSets size limitation for length of a collection.\nApplicable to: **slices**, **maps**.\nPossible values of **N**: 2, 4.\n\n###### \"nil_if_empty\"\n\nDeserialize empty slice into `nil` instead of `[]ElemType{}`.\nApplicable to: **slices.**\n\n**NOTE:** you can also achive same effect by implementing that logic in `BCSInit()` method.\n\n###### \"bytearr\"\n\nMarks value to be written as slice of bytes.\nAppicable to: **any type**.\n\nThe only difference this flag introduces is that value is prepended by the count of its bytes. This might be useful to be able to skip value without knowing its actual structure.\n\n```\ntype TestStruct struct {\n   A int32\n   B int32 `bcs:\"bytearr\"\n}\n\nbcs.Marshal(\u0026TestStruct{A: 10, B: 10}) // []byte{\n                                       //       10, 0, 0, 0,   \u003c-- A\n                                       //    4, 10, 0, 0, 0,   \u003c-- B (notice 4 added the bytes of a value)\n                                       // }\n```\n\n###### \"not_enum\"\n\nForces interface field to be encoded/decoded as plain value and not as enumeration.\nApplicable to: **interfaces, that are registered as enums.**\n\n## Performance considerations\n\n#### Prefer passing pointer into Encode()\n\nUnlike from function `Marshal`(), method `Encode`() accepts both value and pointer. But passing by value will force encoder to copy value to make it addressable to support `MarshalBCS`() method with pointer receiver. It will also not work properly when interface is passed by value, because value is unpacked and packed again as `any` thus information about type of initial interface will be lost.\nSo it is better to pass a pointer always when it is easy to do.\n\n#### Serialization of byte arrays is optimized\n\nArrays of bytes, whose elements does not have any customizations, are directly copied into/from the stream.\n\n#### Serialization of arrays of intergers is NOT yet optimized\n\nIf elements of array are of integer type, and they dont have any customization specified for them (except of `\"type=T\"`), serialization of such array could be optimized to avoid redudant calls for each array element. But this not done specifically to keep code simple while it is maturing.\n\n#### Type parsing is cached\n\nUpon serialization the types are checked for the presense of customizations. This make take significant time.\nTo improve that, the type information is stored in cache.\nTo avoid global mutex locks when reading/writing cache, atomic swapping is used instead.\nIt works like that:\n\n* When coder is created, it get pointer to the current version of cache.\n* Current version of cache is only read, never written, so multiple encoders can read it at the same time.\n* When coder is done with coding, it creates new cache with updated information.\n* Then it atomically swaps the pointer to the new cache with the pointer to the current cache.\n* Multiple coders may update cache, thus overwritting modifications of each other. But it is not a problem, because\n  the info is only extended by them, so eventually cache will have information about all types.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiotaledger%2Fbcs-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fiotaledger%2Fbcs-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiotaledger%2Fbcs-go/lists"}