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