package level import ( "encoding/json" "fmt" "git.kirsle.net/apps/doodle/render" ) // Types of chunks. const ( MapType int = iota GridType ) // Chunk holds a single portion of the pixel canvas. type Chunk struct { Type int // map vs. 2D array. Accessor } // JSONChunk holds a lightweight (interface-free) copy of the Chunk for // unmarshalling JSON files from disk. type JSONChunk struct { Type int `json:"type"` Data json.RawMessage `json:"data"` } // Accessor provides a high-level API to interact with absolute pixel coordinates // while abstracting away the details of how they're stored. type Accessor interface { Inflate(*Palette) error Iter() <-chan Pixel IterViewport(viewport render.Rect) <-chan Pixel Get(render.Point) (*Swatch, error) Set(render.Point, *Swatch) error Delete(render.Point) error Len() int MarshalJSON() ([]byte, error) UnmarshalJSON([]byte) error } // NewChunk creates a new chunk. func NewChunk() *Chunk { return &Chunk{ Type: MapType, Accessor: NewMapAccessor(), } } // Usage returns the percent of free space vs. allocated pixels in the chunk. func (c *Chunk) Usage(size int) float64 { return float64(c.Len()) / float64(size) } // MarshalJSON writes the chunk to JSON. func (c *Chunk) MarshalJSON() ([]byte, error) { data, err := c.Accessor.MarshalJSON() if err != nil { return []byte{}, err } generic := &JSONChunk{ Type: c.Type, Data: data, } b, err := json.Marshal(generic) return b, err } // UnmarshalJSON loads the chunk from JSON and uses the correct accessor to // parse the inner details. func (c *Chunk) UnmarshalJSON(b []byte) error { // Parse it generically so we can hand off the inner "data" object to the // right accessor for unmarshalling. generic := &JSONChunk{} err := json.Unmarshal(b, generic) if err != nil { return fmt.Errorf("Chunk.UnmarshalJSON: failed to unmarshal into generic JSONChunk type: %s", err) } switch c.Type { case MapType: c.Accessor = NewMapAccessor() return c.Accessor.UnmarshalJSON(generic.Data) default: return fmt.Errorf("Chunk.UnmarshalJSON: unsupported chunk type '%d'", c.Type) } }