I made CloseWithError work more similarly to io.Pipe(). CloseWithError effects the error with which the other end of the pipe will return, the same side will return io.ErrClosedPipe.
Also, Close() called concurrently with a Write should cause it to unblock and return (with an error).
Previously, when Closing a concurrent Write would continue to attempt to write to the buffer until successful (leading to it blocking indefinitely if you stopped reading data off the buffer). Now if the writer is awaiting space in the buffer, and is canceled via Close(), it may or may not add the pending data to the buffer, but will return an appropriate error if it fails to add it and return promptly.