diff --git a/buffer.go b/buffer.go index 659a63e..fee6658 100644 --- a/buffer.go +++ b/buffer.go @@ -1,5 +1,7 @@ package stone +import "sync" + // Color represents all the different colors a cell can be. type Color uint8 @@ -65,6 +67,10 @@ type Buffer struct { x int y int } + + // This should be write locked when resizing the buffer, and read locked + // when writing to cells or reading information about the buffer. + lock sync.RWMutex } func (buffer *Buffer) isOutOfBounds (x, y int) (outOfBounds bool) { @@ -78,6 +84,9 @@ func (buffer *Buffer) isOutOfBounds (x, y int) (outOfBounds bool) { // Size returns the width and height of the buffer. func (buffer *Buffer) Size () (width, height int) { + buffer.lock.RLock() + defer buffer.lock.RUnlock() + width = buffer.width height = buffer.height return @@ -93,6 +102,9 @@ func (buffer *Buffer) SetDot (x, y int) { // Cell returns the cell at the specified x and y coordinates. If the // coordinates are out of bounds, this method will return a blank cell. func (buffer *Buffer) Cell (x, y int) (cell Cell) { + buffer.lock.RLock() + defer buffer.lock.RUnlock() + if buffer.isOutOfBounds(x, y) { return } cell = buffer.content[x + y * buffer.width] return @@ -100,6 +112,9 @@ func (buffer *Buffer) Cell (x, y int) (cell Cell) { // SetColor sets the color of the cell at the specified x and y coordinates. func (buffer *Buffer) SetColor (x, y int, color Color) { + buffer.lock.RLock() + defer buffer.lock.RUnlock() + if buffer.isOutOfBounds(x, y) { return } index := x + y * buffer.width buffer.clean[index] = buffer.content[index].color == color @@ -109,6 +124,9 @@ func (buffer *Buffer) SetColor (x, y int, color Color) { // SetSize sets the width and height of the buffer. This clears all data in the // buffer. If the width or height is negative, this method does nothing. func (buffer *Buffer) SetSize (width, height int) { + buffer.lock.Lock() + defer buffer.lock.Unlock() + if width < 0 || height < 0 { return } buffer.width = width buffer.height = height @@ -121,6 +139,9 @@ func (buffer *Buffer) SetSize (width, height int) { // SetStyle sets the style of the cell at the specified x and y coordinates. func (buffer *Buffer) SetStyle (x, y int, style Style) { + buffer.lock.RLock() + defer buffer.lock.RUnlock() + if buffer.isOutOfBounds(x, y) { return } index := x + y * buffer.width buffer.clean[index] = buffer.content[index].style == style @@ -129,6 +150,9 @@ func (buffer *Buffer) SetStyle (x, y int, style Style) { // SetRune sets the rune of the cell at the specified x and y coordinates. func (buffer *Buffer) SetRune (x, y int, content rune) { + buffer.lock.RLock() + defer buffer.lock.RUnlock() + if buffer.isOutOfBounds(x, y) { return } index := x + y * buffer.width buffer.clean[index] = buffer.content[index].content == content @@ -138,6 +162,9 @@ func (buffer *Buffer) SetRune (x, y int, content rune) { // Write writes data stored in a byte slice to the buffer at the current dot // position. This makes Buffer an io.Writer. func (buffer *Buffer) Write (bytes []byte) (bytesWritten int, err error) { + buffer.lock.RLock() + defer buffer.lock.RUnlock() + text := string(bytes) bytesWritten = len(bytes) @@ -153,6 +180,9 @@ func (buffer *Buffer) Write (bytes []byte) (bytesWritten int, err error) { // Clean returns whether or not the cell at the specified x and y coordinates is // clean. func (buffer *Buffer) Clean (x, y int) (clean bool) { + buffer.lock.RLock() + defer buffer.lock.RUnlock() + if buffer.isOutOfBounds(x, y) { return } clean = buffer.clean[x + y * buffer.width] return @@ -160,6 +190,9 @@ func (buffer *Buffer) Clean (x, y int) (clean bool) { // MarkClean marks the cell at the specified x and y coordinates as clean. func (buffer *Buffer) MarkClean (x, y int) { + buffer.lock.RLock() + defer buffer.lock.RUnlock() + if buffer.isOutOfBounds(x, y) { return } buffer.clean[x + y * buffer.width] = true }