1<?php
2namespace GuzzleHttp\Psr7;
3
4use Psr\Http\Message\StreamInterface;
5
6/**
7 * Provides a buffer stream that can be written to to fill a buffer, and read
8 * from to remove bytes from the buffer.
9 *
10 * This stream returns a "hwm" metadata value that tells upstream consumers
11 * what the configured high water mark of the stream is, or the maximum
12 * preferred size of the buffer.
13 */
14class BufferStream implements StreamInterface
15{
16    private $hwm;
17    private $buffer = '';
18
19    /**
20     * @param int $hwm High water mark, representing the preferred maximum
21     *                 buffer size. If the size of the buffer exceeds the high
22     *                 water mark, then calls to write will continue to succeed
23     *                 but will return false to inform writers to slow down
24     *                 until the buffer has been drained by reading from it.
25     */
26    public function __construct($hwm = 16384)
27    {
28        $this->hwm = $hwm;
29    }
30
31    public function __toString()
32    {
33        return $this->getContents();
34    }
35
36    public function getContents()
37    {
38        $buffer = $this->buffer;
39        $this->buffer = '';
40
41        return $buffer;
42    }
43
44    public function close()
45    {
46        $this->buffer = '';
47    }
48
49    public function detach()
50    {
51        $this->close();
52    }
53
54    public function getSize()
55    {
56        return strlen($this->buffer);
57    }
58
59    public function isReadable()
60    {
61        return true;
62    }
63
64    public function isWritable()
65    {
66        return true;
67    }
68
69    public function isSeekable()
70    {
71        return false;
72    }
73
74    public function rewind()
75    {
76        $this->seek(0);
77    }
78
79    public function seek($offset, $whence = SEEK_SET)
80    {
81        throw new \RuntimeException('Cannot seek a BufferStream');
82    }
83
84    public function eof()
85    {
86        return strlen($this->buffer) === 0;
87    }
88
89    public function tell()
90    {
91        throw new \RuntimeException('Cannot determine the position of a BufferStream');
92    }
93
94    /**
95     * Reads data from the buffer.
96     */
97    public function read($length)
98    {
99        $currentLength = strlen($this->buffer);
100
101        if ($length >= $currentLength) {
102            // No need to slice the buffer because we don't have enough data.
103            $result = $this->buffer;
104            $this->buffer = '';
105        } else {
106            // Slice up the result to provide a subset of the buffer.
107            $result = substr($this->buffer, 0, $length);
108            $this->buffer = substr($this->buffer, $length);
109        }
110
111        return $result;
112    }
113
114    /**
115     * Writes data to the buffer.
116     */
117    public function write($string)
118    {
119        $this->buffer .= $string;
120
121        // TODO: What should happen here?
122        if (strlen($this->buffer) >= $this->hwm) {
123            return false;
124        }
125
126        return strlen($string);
127    }
128
129    public function getMetadata($key = null)
130    {
131        if ($key == 'hwm') {
132            return $this->hwm;
133        }
134
135        return $key ? null : [];
136    }
137}
138