diff --git a/CHANGELOG.md b/CHANGELOG.md
index 07ff7c9d56220b11e1a93cf3c1e4d1c59d9ab74e..3af8fc876de102834af36e4dcd1428c9940b34d1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,3 +3,4 @@
 **bugfix release**
 
 * fixed import problem
+* added 
diff --git a/docs/coding/structures.rst b/docs/coding/structures.rst
index e7486d0e98c87b4ba1607b2d609eefbb90bf0580..79b679ff16e34446728494b52dd4d56575223efc 100644
--- a/docs/coding/structures.rst
+++ b/docs/coding/structures.rst
@@ -6,6 +6,12 @@ Structures
     :members:
 
 
+PushIterable
+------------
+
+.. autoclass:: satella.coding.structures.PushIterable
+    :members:
+
 SyncableDroppable
 -----------------
 
diff --git a/satella/__init__.py b/satella/__init__.py
index 4895c882f533b90563a406c778c38e7358f59620..e824526d10fda2a26f44ff378e117a98e44db940 100644
--- a/satella/__init__.py
+++ b/satella/__init__.py
@@ -1 +1 @@
-__version__ = '2.15.3'
+__version__ = '2.15.4'
diff --git a/satella/coding/structures/__init__.py b/satella/coding/structures/__init__.py
index c1d21f02a29520cef933d7cb08d42721dc4209d0..e0efee2bedfa722402e4b9061e84ebb95675d5cb 100644
--- a/satella/coding/structures/__init__.py
+++ b/satella/coding/structures/__init__.py
@@ -18,8 +18,10 @@ from .typednamedtuple import typednamedtuple
 from .lru import LRU
 from .syncable_droppable import DBStorage, SyncableDroppable
 from .tuples import Vector
+from .push_iterable import PushIterable
 
 __all__ = [
+    'PushIterable',
     'Vector',
     'DBStorage', 'SyncableDroppable',
     'LRU',
diff --git a/satella/coding/structures/push_iterable.py b/satella/coding/structures/push_iterable.py
new file mode 100644
index 0000000000000000000000000000000000000000..4daad6ef7f2f47df979b6b5975240ba3f369aa21
--- /dev/null
+++ b/satella/coding/structures/push_iterable.py
@@ -0,0 +1,66 @@
+import typing as tp
+from collections import deque
+
+from satella.coding.typing import T
+
+
+class PushIterable(tp.Generic[T]):
+    """
+    An iterable that you can add elements to it's head, and they will be popped
+    before this iterable is consumed when a pop is called.
+
+    Example:
+
+    .. code-block:: python
+
+        a = PushIterable([1, 2, 3])
+        assert a.pop() == 1
+        a.push(0)
+        assert a.pop() == 0
+        assert a.pop() == 2
+        a.push(0)
+        a.push(1)
+        assert a.pop() == 1
+        assert a.pop() == 0
+        a.push_left(0)
+        a.push_left(1)
+        assert a.pop() == 0
+        assert a.pop() == 1
+        assert a.pop() == 3
+        assertRaises(StopIteration, a.pop)
+    """
+    def __init__(self, iterable: tp.Iterable[T]):
+        self.iterable = iter(iterable)
+        self.collection = deque()
+
+    def pop(self) -> T:
+        """
+        Return next element from the stack
+        :return: a next element
+        """
+        if not self.collection:
+            return next(self.iterable)
+        else:
+            return self.collection.pop()
+
+    def __iter__(self):
+        return self
+
+    def __next__(self) -> T:
+        return self.pop()
+
+    def push(self, item: T) -> None:
+        """
+        Push an item so that next pop will retrieve this item
+
+        :param item: item to push
+        """
+        self.collection.append(item)
+
+    def push_left(self, item):
+        """
+        Push an item so that last pop from internal buffer will retrieve this item
+
+        :param item: item to push
+        """
+        self.collection.appendleft(item)
diff --git a/tests/test_coding/test_structures.py b/tests/test_coding/test_structures.py
index 8b5448490e4820bbc9ee432db0107d4596f09b86..9d7a7605b8b5fcb1f1aa1a6f40d068b8ee031b4a 100644
--- a/tests/test_coding/test_structures.py
+++ b/tests/test_coding/test_structures.py
@@ -14,11 +14,29 @@ from satella.coding.structures import TimeBasedHeap, Heap, typednamedtuple, \
     DirtyDict, KeyAwareDefaultDict, Proxy, ReprableMixin, TimeBasedSetHeap, ExpiringEntryDict, SelfCleaningDefaultDict, \
     CacheDict, StrEqHashableMixin, ComparableIntEnum, HashableIntEnum, ComparableAndHashableBy, \
     ComparableAndHashableByInt, SparseMatrix, ExclusiveWritebackCache, Subqueue, \
-    CountingDict, ComparableEnum, LRU, LRUCacheDict, Vector, DefaultDict
+    CountingDict, ComparableEnum, LRU, LRUCacheDict, Vector, DefaultDict, PushIterable
 
 
 class TestMisc(unittest.TestCase):
 
+    def test_push_iterable(self):
+
+        a = PushIterable([1, 2, 3])
+        self.assertEqual(a.pop(), 1)
+        a.push(0)
+        self.assertEqual(a.pop(), 0)
+        self.assertEqual(a.pop(), 2)
+        a.push(0)
+        a.push(1)
+        self.assertEqual(a.pop(), 1)
+        self.assertEqual(a.pop(), 0)
+        a.push_left(0)
+        a.push_left(1)
+        self.assertEqual(a.pop(), 0)
+        self.assertEqual(a.pop(), 1)
+        self.assertEqual(a.pop(), 3)
+        self.assertRaises(StopIteration, a.pop)
+
     def test_default_dict(self):
         a = DefaultDict(lambda: '')
         a[2]