Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge of fernomac/ion-go #26

Merged
merged 57 commits into from
May 20, 2020
Merged
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
1750293
basic text writer implementation
fernomac Jun 10, 2019
7ac7e33
go fmt
fernomac Jun 10, 2019
f8208a5
parsing decimals and some math
fernomac Jun 10, 2019
797d9a9
more decimal bikeshedding
fernomac Jun 11, 2019
46c843f
refactorizing to avoid circular references
fernomac Jun 11, 2019
b5b2778
fine, go fmt
fernomac Jun 12, 2019
303e8aa
symboltable, reader interface
fernomac Jun 15, 2019
7b32f6c
start of tokenizer
fernomac Jun 21, 2019
dcb9d96
minor fixups
fernomac Jun 24, 2019
f1d6578
Initial textreader impl
fernomac Jun 27, 2019
b5f7d6b
handling for special symbols
fernomac Jun 27, 2019
e4a4ba2
strings and integers
fernomac Jun 27, 2019
e75397a
floats, doubles, timestamps
fernomac Jul 2, 2019
ba3adeb
blobs and clobs
fernomac Jul 3, 2019
8f8d5dc
structs and lists
fernomac Jul 14, 2019
66de8b9
sexps
fernomac Jul 15, 2019
c11d8db
Adding test data submodule
fernomac Jul 15, 2019
a69cbd3
standard test suite for text reader, bugfixes
fernomac Jul 15, 2019
df048f4
test refactoring, bugfixes
fernomac Jul 16, 2019
1991b65
Truncate text timestamps with more than nanosecond precision
fernomac Jul 22, 2019
7532672
marshal
fernomac Jul 22, 2019
8400307
make marshaller public
fernomac Jul 23, 2019
e35a521
Writer.WriteValue
fernomac Jul 23, 2019
9c1a186
marshaller->encoder
fernomac Jul 23, 2019
d5ef309
unmarshal
fernomac Jul 29, 2019
22e024c
tackling some todos
fernomac Jul 29, 2019
7501e3a
binary writer
fernomac Aug 6, 2019
a9ee27b
stuff and stuff
fernomac Aug 6, 2019
c5e0d4c
refactoring binary writer
fernomac Aug 9, 2019
cb4e1ba
changing some things around here
fernomac Aug 10, 2019
5abeffa
start of binaryreader
fernomac Aug 14, 2019
5030a04
more binaryreader
fernomac Aug 19, 2019
6996d98
more binary reading
fernomac Aug 26, 2019
94e39d6
bugfixes, docs, and refactoring
fernomac Aug 26, 2019
aa2c302
Refactoring things
fernomac Sep 1, 2019
8793670
More refactoring
fernomac Sep 1, 2019
b53948d
Even more refactoring
fernomac Sep 1, 2019
c863cd2
README, LICENSE, etc
fernomac Sep 1, 2019
02beac6
improved error handling, refactoring
fernomac Sep 2, 2019
97c2660
Point at amzn/ion-go, which exists now (#1)
fernomac May 7, 2020
28b4adf
merge fernomac/ion-go
therapon May 8, 2020
823a199
Removed older code
therapon May 8, 2020
9bf5542
Move into ion folder
therapon May 8, 2020
684e59a
moved files into ion folder
therapon May 8, 2020
02fdea8
Updates to blacklist and location of ion-tests
therapon May 8, 2020
58c7b21
keeping internal folder
therapon May 8, 2020
8b3a97d
Remove leftover line from conflict resolution
therapon May 8, 2020
9769d14
Removing and adding later to kick GitHub Action
May 8, 2020
40bd845
Adding back GitHub Action
May 8, 2020
678efdf
Trying code coverage
therapon May 8, 2020
16d77f3
Adding codecov token
therapon May 8, 2020
3cc0061
Kick the build again
therapon May 8, 2020
b1bb777
Use latest codecov action version
therapon May 8, 2020
2dff52b
Update NOTICE per Apache v2
May 8, 2020
9ae6004
Adding PR template
May 8, 2020
749c0a7
fix go import in README
therapon May 17, 2020
0cddde4
Address PR comments
therapon May 17, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,12 @@ jobs:
- name: Build
run: go build -v ./...

- name: Test
run: go test -v ./...
- name: Test with coverage
run: go test -v ./... -coverprofile coverage.txt


- name: Upload Coverage report to CodeCov
uses: codecov/codecov-action@v1
with:
token: ${{secrets.CODECOV_TOKEN}}
file: ./coverage.txt
244 changes: 236 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,250 @@ $ goimports -w .

It is recommended that you hook this in your favorite IDE (`Tools` > `File Watchers` in Goland, for example).

## Usage

Import `github.com/amzn/ion-go` and you're off to the races.
therapon marked this conversation as resolved.
Show resolved Hide resolved

### Marshaling and Unmarshaling

Similar to Golang's built-in [json](https://golang.org/pkg/encoding/json/) package,
you can marshal and unmarshal go types to Ion. Marshaling requires you to specify
therapon marked this conversation as resolved.
Show resolved Hide resolved
whether you'd like text or binary Ion. Unmarshaling is smart enough to do the right
thing. Both respect json name tags, and `Marshal` honors omitempty.

```Go
type T struct {
A string
B struct {
RenamedC int `json:"C"`
D []int `json:",omitempty"`
}
}

func main() {
t := T{}

err := ion.Unmarshal([]byte("{A:\"Ion!\",B:{C:2,D:[3,4]}}"), &t)
therapon marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
panic(err)
}
fmt.Printf("--- t:\n%v\n\n", t)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These Printfs should be followed with a comment that shows what would be printed. The code can't be copy/pasted into a playground because it relies on an external library.


text, err := ion.MarshalText(&t)
if err != nil {
panic(err)
}
fmt.Printf("--- text:\n%s\n\n", string(text))

binary, err := ion.MarshalBinary(&t)
if err != nil {
panic(err)
}
fmt.Printf("--- binary:\n%X\n\n", binary)
}
```

### Encoding and Decoding

To read or write multiple values at once, use an `Encoder` or `Decoder`:

```Go
func main() {
dec := ion.NewTextDecoder(os.Stdin)
enc := ion.NewBinaryEncoder(os.Stdout)

for {
// Decode one Ion whole value from stdin.
val, err := dec.Decode()
if err == ion.ErrNoInput {
break
} else if err != nil {
panic(err)
}

// Encode it to stdout.
if err := enc.Encode(val); err != nil {
panic(err)
}
}

if err := enc.Finish(); err != nil {
panic(err)
}
}
```

### Reading and Writing

For low-level streaming read and write access, use a `Reader` or `Writer`.

```Go
func copy(in ion.Reader, out ion.Writer) {
therapon marked this conversation as resolved.
Show resolved Hide resolved
for in.Next() {
name := in.FieldName()
if name != "" {
out.FieldName(name)
}

annos := in.Annotations()
if len(annos) > 0 {
out.Annotations(annos...)
}

switch in.Type() {
case ion.BoolType:
val, err := in.BoolValue()
if err != nil {
panic(err)
}
out.WriteBool(val)

case ion.IntType:
val, err := in.Int64Value()
if err != nil {
panic(err)
}
out.WriteInt(val)

case ion.StringType:
val, err := in.StringValue()
if err != nil {
panic(err)
}
out.WriteString(val)

case ion.ListType:
in.StepIn()
out.BeginList()
copy(in, out)
in.StepOut()
out.EndList()

case ion.StructType:
in.StepIn()
out.BeginStruct()
copy(in, out)
in.StepOut()
out.EndStruct()
}
}

if in.Err() != nil {
panic(in.Err())
}
}

func main() {
in := ion.NewReader(os.Stdin)
out := ion.NewBinaryWriter(os.Stdout)

copy(in, out)

if err := out.Finish(); err != nil {
panic(err)
}
}
```

### Symbol Tables

By default, when writing binary Ion, a local symbol table is built as you write
values (which are buffered in memory until you call `Finish` so the symbol table
can be written out first). You can optionally provide one or more
`SharedSymbolTable`s to the writer, which it will reference as needed rather
than directly including those symbols in the local symbol table.

```Go
type Item struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
}

var ItemSharedSymbols = ion.NewSharedSymbolTable("item", 1, []string{
"item",
"id",
"name",
"description",
})

type SpicyItem struct {
Item
Spiciness int `json:"spiciness"`
}

func WriteSpicyItemsTo(out io.Writer, items []SpicyItem) error {
writer := ion.NewBinaryWriter(out, ItemSharedSymbols)

for _, item := range items {
writer.Annotation("item")
if err := ion.EncodeTo(writer, item); err != nil {
return err
}
}

return writer.Finish()
}
```

You can alternatively provide the writer with a complete, pre-built local symbol table.
This allows values to be written without buffering, however any attempt to write a
symbol that is not included in the symbol table will result in an error:

```Go
func WriteItemsToLST(out io.Writer, items []SpicyItem) error {
lst := ion.NewLocalSymbolTable([]SharedSymbolTable{ItemSharedSymbols}, []string{
"spiciness",
})

writer := ion.NewBinaryWriterLST(out, lst)

for _, item := range items {
writer.Annotation("item")
if err := ion.EncodeTo(writer, item); err != nil {
return err
}
}

return writer.Finish()
}
```

When reading binary Ion, shared symbol tables are provided by a `Catalog`. A basic
catalog can be constructed by calling `NewCatalog`; a smarter implementation may
load shared symbol tables from a database on demand.

```Go

func ReadItemsFrom(in io.Reader) ([]Item, error) {
item := Item{}
items := []Item{}

cat := ion.NewCatalog(ItemSharedSymbols)
dec := ion.NewDecoder(ion.NewReaderCat(in, cat))

for {
err := dec.DecodeTo(&item)
if err == ion.ErrNoInput {
return items, nil
}
if err != nil {
return nil, err
}

items = append(items, item)
}
}
```
## Notes

* This package only supports text as UTF-8. It does not support the UTF-16 or UTF-32 forms.
* Only a text and binary parsers, and a sketch of the types have been implemented so far.
* The `Float` type is limited to the minimum and maximum values that Go is able to handle with float64. These values
are approximately `1.797693e+308` and `4.940656e-324`. Values that are too large will round to infinity and
values that are too small will round to zero.
* Textual representation of `Timestamp` currently stops at microsecond precision.

## TODO

* Symbol table construction and verification.
* Define the external interfaces for marshalling and unmarshalling.
* Serializing Values to the textual and binary forms.
Expand All @@ -78,10 +312,4 @@ It is recommended that you hook this in your favorite IDE (`Tools` > `File Watch
* Make the `Timestamp` type handle the case of unknown local offsets.
* Make the `Float` and `Decimal` types recognize negative zero.

## Usage

```go
package main

// TODO
```
6 changes: 0 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
module github.com/amzn/ion-go

go 1.13

require (
github.com/google/go-cmp v0.4.0
github.com/pkg/errors v0.9.1
github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114
)
Empty file added internal/.keep
Empty file.
Loading