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