diff --git a/docs/assets/search.js b/docs/assets/search.js index df164c4..5f074ef 100644 --- a/docs/assets/search.js +++ b/docs/assets/search.js @@ -1 +1 @@ -window.searchData = JSON.parse("{\"kinds\":{\"128\":\"Class\",\"512\":\"Constructor\",\"1024\":\"Property\",\"2048\":\"Method\",\"262144\":\"Accessor\"},\"rows\":[{\"id\":0,\"kind\":128,\"name\":\"Lock\",\"url\":\"classes/Lock.html\",\"classes\":\"tsd-kind-class\"},{\"id\":1,\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/Lock.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"Lock\"},{\"id\":2,\"kind\":1024,\"name\":\"lock\",\"url\":\"classes/Lock.html#lock\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Lock\"},{\"id\":3,\"kind\":1024,\"name\":\"release\",\"url\":\"classes/Lock.html#release\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Lock\"},{\"id\":4,\"kind\":1024,\"name\":\"_count\",\"url\":\"classes/Lock.html#_count\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Lock\"},{\"id\":5,\"kind\":1024,\"name\":\"acquire\",\"url\":\"classes/Lock.html#acquire\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"Lock\"},{\"id\":6,\"kind\":262144,\"name\":\"count\",\"url\":\"classes/Lock.html#count\",\"classes\":\"tsd-kind-get-signature tsd-parent-kind-class\",\"parent\":\"Lock\"},{\"id\":7,\"kind\":2048,\"name\":\"isLocked\",\"url\":\"classes/Lock.html#isLocked\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Lock\"},{\"id\":8,\"kind\":2048,\"name\":\"waitForUnlock\",\"url\":\"classes/Lock.html#waitForUnlock\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Lock\"},{\"id\":9,\"kind\":2048,\"name\":\"withF\",\"url\":\"classes/Lock.html#withF\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"Lock\"},{\"id\":10,\"kind\":2048,\"name\":\"withG\",\"url\":\"classes/Lock.html#withG\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"Lock\"},{\"id\":11,\"kind\":128,\"name\":\"RWLockReader\",\"url\":\"classes/RWLockReader.html\",\"classes\":\"tsd-kind-class\"},{\"id\":12,\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/RWLockReader.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"RWLockReader\"},{\"id\":13,\"kind\":1024,\"name\":\"_readerCount\",\"url\":\"classes/RWLockReader.html#_readerCount\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockReader\"},{\"id\":14,\"kind\":1024,\"name\":\"_writerCount\",\"url\":\"classes/RWLockReader.html#_writerCount\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockReader\"},{\"id\":15,\"kind\":1024,\"name\":\"lock\",\"url\":\"classes/RWLockReader.html#lock\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockReader\"},{\"id\":16,\"kind\":1024,\"name\":\"release\",\"url\":\"classes/RWLockReader.html#release\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockReader\"},{\"id\":17,\"kind\":1024,\"name\":\"acquireRead\",\"url\":\"classes/RWLockReader.html#acquireRead\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"RWLockReader\"},{\"id\":18,\"kind\":1024,\"name\":\"acquireWrite\",\"url\":\"classes/RWLockReader.html#acquireWrite\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"RWLockReader\"},{\"id\":19,\"kind\":262144,\"name\":\"readerCount\",\"url\":\"classes/RWLockReader.html#readerCount\",\"classes\":\"tsd-kind-get-signature tsd-parent-kind-class\",\"parent\":\"RWLockReader\"},{\"id\":20,\"kind\":262144,\"name\":\"writerCount\",\"url\":\"classes/RWLockReader.html#writerCount\",\"classes\":\"tsd-kind-get-signature tsd-parent-kind-class\",\"parent\":\"RWLockReader\"},{\"id\":21,\"kind\":2048,\"name\":\"isLocked\",\"url\":\"classes/RWLockReader.html#isLocked\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RWLockReader\"},{\"id\":22,\"kind\":2048,\"name\":\"waitForUnlock\",\"url\":\"classes/RWLockReader.html#waitForUnlock\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RWLockReader\"},{\"id\":23,\"kind\":2048,\"name\":\"withReadF\",\"url\":\"classes/RWLockReader.html#withReadF\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"RWLockReader\"},{\"id\":24,\"kind\":2048,\"name\":\"withWriteF\",\"url\":\"classes/RWLockReader.html#withWriteF\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"RWLockReader\"},{\"id\":25,\"kind\":2048,\"name\":\"withReadG\",\"url\":\"classes/RWLockReader.html#withReadG\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"RWLockReader\"},{\"id\":26,\"kind\":2048,\"name\":\"withWriteG\",\"url\":\"classes/RWLockReader.html#withWriteG\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"RWLockReader\"},{\"id\":27,\"kind\":128,\"name\":\"RWLockWriter\",\"url\":\"classes/RWLockWriter.html\",\"classes\":\"tsd-kind-class\"},{\"id\":28,\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/RWLockWriter.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"RWLockWriter\"},{\"id\":29,\"kind\":1024,\"name\":\"readersLock\",\"url\":\"classes/RWLockWriter.html#readersLock\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockWriter\"},{\"id\":30,\"kind\":1024,\"name\":\"writersLock\",\"url\":\"classes/RWLockWriter.html#writersLock\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockWriter\"},{\"id\":31,\"kind\":1024,\"name\":\"readersRelease\",\"url\":\"classes/RWLockWriter.html#readersRelease\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockWriter\"},{\"id\":32,\"kind\":1024,\"name\":\"readerCountBlocked\",\"url\":\"classes/RWLockWriter.html#readerCountBlocked\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockWriter\"},{\"id\":33,\"kind\":1024,\"name\":\"_readerCount\",\"url\":\"classes/RWLockWriter.html#_readerCount\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockWriter\"},{\"id\":34,\"kind\":1024,\"name\":\"_writerCount\",\"url\":\"classes/RWLockWriter.html#_writerCount\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockWriter\"},{\"id\":35,\"kind\":1024,\"name\":\"acquireRead\",\"url\":\"classes/RWLockWriter.html#acquireRead\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"RWLockWriter\"},{\"id\":36,\"kind\":1024,\"name\":\"acquireWrite\",\"url\":\"classes/RWLockWriter.html#acquireWrite\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"RWLockWriter\"},{\"id\":37,\"kind\":262144,\"name\":\"readerCount\",\"url\":\"classes/RWLockWriter.html#readerCount\",\"classes\":\"tsd-kind-get-signature tsd-parent-kind-class\",\"parent\":\"RWLockWriter\"},{\"id\":38,\"kind\":262144,\"name\":\"writerCount\",\"url\":\"classes/RWLockWriter.html#writerCount\",\"classes\":\"tsd-kind-get-signature tsd-parent-kind-class\",\"parent\":\"RWLockWriter\"},{\"id\":39,\"kind\":2048,\"name\":\"isLocked\",\"url\":\"classes/RWLockWriter.html#isLocked\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RWLockWriter\"},{\"id\":40,\"kind\":2048,\"name\":\"waitForUnlock\",\"url\":\"classes/RWLockWriter.html#waitForUnlock\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RWLockWriter\"},{\"id\":41,\"kind\":2048,\"name\":\"withReadF\",\"url\":\"classes/RWLockWriter.html#withReadF\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"RWLockWriter\"},{\"id\":42,\"kind\":2048,\"name\":\"withWriteF\",\"url\":\"classes/RWLockWriter.html#withWriteF\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"RWLockWriter\"},{\"id\":43,\"kind\":2048,\"name\":\"withReadG\",\"url\":\"classes/RWLockWriter.html#withReadG\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"RWLockWriter\"},{\"id\":44,\"kind\":2048,\"name\":\"withWriteG\",\"url\":\"classes/RWLockWriter.html#withWriteG\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"RWLockWriter\"}],\"index\":{\"version\":\"2.3.9\",\"fields\":[\"name\",\"parent\"],\"fieldVectors\":[[\"name/0\",[0,12.26]],[\"parent/0\",[]],[\"name/1\",[1,25.759]],[\"parent/1\",[0,1.191]],[\"name/2\",[0,12.26]],[\"parent/2\",[0,1.191]],[\"name/3\",[2,29.124]],[\"parent/3\",[0,1.191]],[\"name/4\",[3,34.232]],[\"parent/4\",[0,1.191]],[\"name/5\",[4,34.232]],[\"parent/5\",[0,1.191]],[\"name/6\",[5,34.232]],[\"parent/6\",[0,1.191]],[\"name/7\",[6,25.759]],[\"parent/7\",[0,1.191]],[\"name/8\",[7,25.759]],[\"parent/8\",[0,1.191]],[\"name/9\",[8,34.232]],[\"parent/9\",[0,1.191]],[\"name/10\",[9,34.232]],[\"parent/10\",[0,1.191]],[\"name/11\",[10,10.253]],[\"parent/11\",[]],[\"name/12\",[1,25.759]],[\"parent/12\",[10,0.996]],[\"name/13\",[11,29.124]],[\"parent/13\",[10,0.996]],[\"name/14\",[12,29.124]],[\"parent/14\",[10,0.996]],[\"name/15\",[0,12.26]],[\"parent/15\",[10,0.996]],[\"name/16\",[2,29.124]],[\"parent/16\",[10,0.996]],[\"name/17\",[13,29.124]],[\"parent/17\",[10,0.996]],[\"name/18\",[14,29.124]],[\"parent/18\",[10,0.996]],[\"name/19\",[15,29.124]],[\"parent/19\",[10,0.996]],[\"name/20\",[16,29.124]],[\"parent/20\",[10,0.996]],[\"name/21\",[6,25.759]],[\"parent/21\",[10,0.996]],[\"name/22\",[7,25.759]],[\"parent/22\",[10,0.996]],[\"name/23\",[17,29.124]],[\"parent/23\",[10,0.996]],[\"name/24\",[18,29.124]],[\"parent/24\",[10,0.996]],[\"name/25\",[19,29.124]],[\"parent/25\",[10,0.996]],[\"name/26\",[20,29.124]],[\"parent/26\",[10,0.996]],[\"name/27\",[21,9.109]],[\"parent/27\",[]],[\"name/28\",[1,25.759]],[\"parent/28\",[21,0.885]],[\"name/29\",[22,34.232]],[\"parent/29\",[21,0.885]],[\"name/30\",[23,34.232]],[\"parent/30\",[21,0.885]],[\"name/31\",[24,34.232]],[\"parent/31\",[21,0.885]],[\"name/32\",[25,34.232]],[\"parent/32\",[21,0.885]],[\"name/33\",[11,29.124]],[\"parent/33\",[21,0.885]],[\"name/34\",[12,29.124]],[\"parent/34\",[21,0.885]],[\"name/35\",[13,29.124]],[\"parent/35\",[21,0.885]],[\"name/36\",[14,29.124]],[\"parent/36\",[21,0.885]],[\"name/37\",[15,29.124]],[\"parent/37\",[21,0.885]],[\"name/38\",[16,29.124]],[\"parent/38\",[21,0.885]],[\"name/39\",[6,25.759]],[\"parent/39\",[21,0.885]],[\"name/40\",[7,25.759]],[\"parent/40\",[21,0.885]],[\"name/41\",[17,29.124]],[\"parent/41\",[21,0.885]],[\"name/42\",[18,29.124]],[\"parent/42\",[21,0.885]],[\"name/43\",[19,29.124]],[\"parent/43\",[21,0.885]],[\"name/44\",[20,29.124]],[\"parent/44\",[21,0.885]]],\"invertedIndex\":[[\"_count\",{\"_index\":3,\"name\":{\"4\":{}},\"parent\":{}}],[\"_readercount\",{\"_index\":11,\"name\":{\"13\":{},\"33\":{}},\"parent\":{}}],[\"_writercount\",{\"_index\":12,\"name\":{\"14\":{},\"34\":{}},\"parent\":{}}],[\"acquire\",{\"_index\":4,\"name\":{\"5\":{}},\"parent\":{}}],[\"acquireread\",{\"_index\":13,\"name\":{\"17\":{},\"35\":{}},\"parent\":{}}],[\"acquirewrite\",{\"_index\":14,\"name\":{\"18\":{},\"36\":{}},\"parent\":{}}],[\"constructor\",{\"_index\":1,\"name\":{\"1\":{},\"12\":{},\"28\":{}},\"parent\":{}}],[\"count\",{\"_index\":5,\"name\":{\"6\":{}},\"parent\":{}}],[\"islocked\",{\"_index\":6,\"name\":{\"7\":{},\"21\":{},\"39\":{}},\"parent\":{}}],[\"lock\",{\"_index\":0,\"name\":{\"0\":{},\"2\":{},\"15\":{}},\"parent\":{\"1\":{},\"2\":{},\"3\":{},\"4\":{},\"5\":{},\"6\":{},\"7\":{},\"8\":{},\"9\":{},\"10\":{}}}],[\"readercount\",{\"_index\":15,\"name\":{\"19\":{},\"37\":{}},\"parent\":{}}],[\"readercountblocked\",{\"_index\":25,\"name\":{\"32\":{}},\"parent\":{}}],[\"readerslock\",{\"_index\":22,\"name\":{\"29\":{}},\"parent\":{}}],[\"readersrelease\",{\"_index\":24,\"name\":{\"31\":{}},\"parent\":{}}],[\"release\",{\"_index\":2,\"name\":{\"3\":{},\"16\":{}},\"parent\":{}}],[\"rwlockreader\",{\"_index\":10,\"name\":{\"11\":{}},\"parent\":{\"12\":{},\"13\":{},\"14\":{},\"15\":{},\"16\":{},\"17\":{},\"18\":{},\"19\":{},\"20\":{},\"21\":{},\"22\":{},\"23\":{},\"24\":{},\"25\":{},\"26\":{}}}],[\"rwlockwriter\",{\"_index\":21,\"name\":{\"27\":{}},\"parent\":{\"28\":{},\"29\":{},\"30\":{},\"31\":{},\"32\":{},\"33\":{},\"34\":{},\"35\":{},\"36\":{},\"37\":{},\"38\":{},\"39\":{},\"40\":{},\"41\":{},\"42\":{},\"43\":{},\"44\":{}}}],[\"waitforunlock\",{\"_index\":7,\"name\":{\"8\":{},\"22\":{},\"40\":{}},\"parent\":{}}],[\"withf\",{\"_index\":8,\"name\":{\"9\":{}},\"parent\":{}}],[\"withg\",{\"_index\":9,\"name\":{\"10\":{}},\"parent\":{}}],[\"withreadf\",{\"_index\":17,\"name\":{\"23\":{},\"41\":{}},\"parent\":{}}],[\"withreadg\",{\"_index\":19,\"name\":{\"25\":{},\"43\":{}},\"parent\":{}}],[\"withwritef\",{\"_index\":18,\"name\":{\"24\":{},\"42\":{}},\"parent\":{}}],[\"withwriteg\",{\"_index\":20,\"name\":{\"26\":{},\"44\":{}},\"parent\":{}}],[\"writercount\",{\"_index\":16,\"name\":{\"20\":{},\"38\":{}},\"parent\":{}}],[\"writerslock\",{\"_index\":23,\"name\":{\"30\":{}},\"parent\":{}}]],\"pipeline\":[]}}"); \ No newline at end of file +window.searchData = JSON.parse("{\"kinds\":{\"4\":\"Namespace\",\"64\":\"Function\",\"128\":\"Class\",\"512\":\"Constructor\",\"1024\":\"Property\",\"2048\":\"Method\",\"65536\":\"Type literal\",\"262144\":\"Accessor\",\"4194304\":\"Type alias\"},\"rows\":[{\"id\":0,\"kind\":128,\"name\":\"Lock\",\"url\":\"classes/Lock.html\",\"classes\":\"tsd-kind-class\"},{\"id\":1,\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/Lock.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"Lock\"},{\"id\":2,\"kind\":1024,\"name\":\"_lock\",\"url\":\"classes/Lock.html#_lock\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Lock\"},{\"id\":3,\"kind\":1024,\"name\":\"_count\",\"url\":\"classes/Lock.html#_count\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"Lock\"},{\"id\":4,\"kind\":2048,\"name\":\"lock\",\"url\":\"classes/Lock.html#lock\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Lock\"},{\"id\":5,\"kind\":262144,\"name\":\"count\",\"url\":\"classes/Lock.html#count\",\"classes\":\"tsd-kind-get-signature tsd-parent-kind-class\",\"parent\":\"Lock\"},{\"id\":6,\"kind\":2048,\"name\":\"isLocked\",\"url\":\"classes/Lock.html#isLocked\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Lock\"},{\"id\":7,\"kind\":2048,\"name\":\"waitForUnlock\",\"url\":\"classes/Lock.html#waitForUnlock\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"Lock\"},{\"id\":8,\"kind\":2048,\"name\":\"withF\",\"url\":\"classes/Lock.html#withF\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"Lock\"},{\"id\":9,\"kind\":2048,\"name\":\"withG\",\"url\":\"classes/Lock.html#withG\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"Lock\"},{\"id\":10,\"kind\":128,\"name\":\"RWLockReader\",\"url\":\"classes/RWLockReader.html\",\"classes\":\"tsd-kind-class\"},{\"id\":11,\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/RWLockReader.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"RWLockReader\"},{\"id\":12,\"kind\":1024,\"name\":\"_readerCount\",\"url\":\"classes/RWLockReader.html#_readerCount\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockReader\"},{\"id\":13,\"kind\":1024,\"name\":\"_writerCount\",\"url\":\"classes/RWLockReader.html#_writerCount\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockReader\"},{\"id\":14,\"kind\":1024,\"name\":\"lock\",\"url\":\"classes/RWLockReader.html#lock\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockReader\"},{\"id\":15,\"kind\":1024,\"name\":\"release\",\"url\":\"classes/RWLockReader.html#release\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockReader\"},{\"id\":16,\"kind\":2048,\"name\":\"read\",\"url\":\"classes/RWLockReader.html#read\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RWLockReader\"},{\"id\":17,\"kind\":2048,\"name\":\"write\",\"url\":\"classes/RWLockReader.html#write\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RWLockReader\"},{\"id\":18,\"kind\":262144,\"name\":\"readerCount\",\"url\":\"classes/RWLockReader.html#readerCount\",\"classes\":\"tsd-kind-get-signature tsd-parent-kind-class\",\"parent\":\"RWLockReader\"},{\"id\":19,\"kind\":262144,\"name\":\"writerCount\",\"url\":\"classes/RWLockReader.html#writerCount\",\"classes\":\"tsd-kind-get-signature tsd-parent-kind-class\",\"parent\":\"RWLockReader\"},{\"id\":20,\"kind\":2048,\"name\":\"isLocked\",\"url\":\"classes/RWLockReader.html#isLocked\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RWLockReader\"},{\"id\":21,\"kind\":2048,\"name\":\"waitForUnlock\",\"url\":\"classes/RWLockReader.html#waitForUnlock\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RWLockReader\"},{\"id\":22,\"kind\":2048,\"name\":\"withReadF\",\"url\":\"classes/RWLockReader.html#withReadF\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"RWLockReader\"},{\"id\":23,\"kind\":2048,\"name\":\"withWriteF\",\"url\":\"classes/RWLockReader.html#withWriteF\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"RWLockReader\"},{\"id\":24,\"kind\":2048,\"name\":\"withReadG\",\"url\":\"classes/RWLockReader.html#withReadG\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"RWLockReader\"},{\"id\":25,\"kind\":2048,\"name\":\"withWriteG\",\"url\":\"classes/RWLockReader.html#withWriteG\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"RWLockReader\"},{\"id\":26,\"kind\":128,\"name\":\"RWLockWriter\",\"url\":\"classes/RWLockWriter.html\",\"classes\":\"tsd-kind-class\"},{\"id\":27,\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/RWLockWriter.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class\",\"parent\":\"RWLockWriter\"},{\"id\":28,\"kind\":1024,\"name\":\"readersLock\",\"url\":\"classes/RWLockWriter.html#readersLock\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockWriter\"},{\"id\":29,\"kind\":1024,\"name\":\"writersLock\",\"url\":\"classes/RWLockWriter.html#writersLock\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockWriter\"},{\"id\":30,\"kind\":1024,\"name\":\"readersRelease\",\"url\":\"classes/RWLockWriter.html#readersRelease\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockWriter\"},{\"id\":31,\"kind\":1024,\"name\":\"readerCountBlocked\",\"url\":\"classes/RWLockWriter.html#readerCountBlocked\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockWriter\"},{\"id\":32,\"kind\":1024,\"name\":\"_readerCount\",\"url\":\"classes/RWLockWriter.html#_readerCount\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockWriter\"},{\"id\":33,\"kind\":1024,\"name\":\"_writerCount\",\"url\":\"classes/RWLockWriter.html#_writerCount\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-protected\",\"parent\":\"RWLockWriter\"},{\"id\":34,\"kind\":2048,\"name\":\"read\",\"url\":\"classes/RWLockWriter.html#read\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RWLockWriter\"},{\"id\":35,\"kind\":2048,\"name\":\"write\",\"url\":\"classes/RWLockWriter.html#write\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RWLockWriter\"},{\"id\":36,\"kind\":262144,\"name\":\"readerCount\",\"url\":\"classes/RWLockWriter.html#readerCount\",\"classes\":\"tsd-kind-get-signature tsd-parent-kind-class\",\"parent\":\"RWLockWriter\"},{\"id\":37,\"kind\":262144,\"name\":\"writerCount\",\"url\":\"classes/RWLockWriter.html#writerCount\",\"classes\":\"tsd-kind-get-signature tsd-parent-kind-class\",\"parent\":\"RWLockWriter\"},{\"id\":38,\"kind\":2048,\"name\":\"isLocked\",\"url\":\"classes/RWLockWriter.html#isLocked\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RWLockWriter\"},{\"id\":39,\"kind\":2048,\"name\":\"waitForUnlock\",\"url\":\"classes/RWLockWriter.html#waitForUnlock\",\"classes\":\"tsd-kind-method tsd-parent-kind-class\",\"parent\":\"RWLockWriter\"},{\"id\":40,\"kind\":2048,\"name\":\"withReadF\",\"url\":\"classes/RWLockWriter.html#withReadF\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"RWLockWriter\"},{\"id\":41,\"kind\":2048,\"name\":\"withWriteF\",\"url\":\"classes/RWLockWriter.html#withWriteF\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"RWLockWriter\"},{\"id\":42,\"kind\":2048,\"name\":\"withReadG\",\"url\":\"classes/RWLockWriter.html#withReadG\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"RWLockWriter\"},{\"id\":43,\"kind\":2048,\"name\":\"withWriteG\",\"url\":\"classes/RWLockWriter.html#withWriteG\",\"classes\":\"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter\",\"parent\":\"RWLockWriter\"},{\"id\":44,\"kind\":4,\"name\":\"utils\",\"url\":\"modules/utils.html\",\"classes\":\"tsd-kind-namespace\"},{\"id\":45,\"kind\":64,\"name\":\"sleep\",\"url\":\"modules/utils.html#sleep\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"id\":46,\"kind\":64,\"name\":\"yieldMicro\",\"url\":\"modules/utils.html#yieldMicro\",\"classes\":\"tsd-kind-function tsd-parent-kind-namespace\",\"parent\":\"utils\"},{\"id\":47,\"kind\":4,\"name\":\"errors\",\"url\":\"modules/errors.html\",\"classes\":\"tsd-kind-namespace\"},{\"id\":48,\"kind\":128,\"name\":\"ErrorAsyncLocks\",\"url\":\"classes/errors.ErrorAsyncLocks.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"id\":49,\"kind\":65536,\"name\":\"__type\",\"url\":\"classes/errors.ErrorAsyncLocks.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-class\",\"parent\":\"errors.ErrorAsyncLocks\"},{\"id\":50,\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorAsyncLocks.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-overwrite\",\"parent\":\"errors.ErrorAsyncLocks\"},{\"id\":51,\"kind\":1024,\"name\":\"data\",\"url\":\"classes/errors.ErrorAsyncLocks.html#data\",\"classes\":\"tsd-kind-property tsd-parent-kind-class\",\"parent\":\"errors.ErrorAsyncLocks\"},{\"id\":52,\"kind\":128,\"name\":\"ErrorAsyncLocksTimeout\",\"url\":\"classes/errors.ErrorAsyncLocksTimeout.html\",\"classes\":\"tsd-kind-class tsd-parent-kind-namespace\",\"parent\":\"errors\"},{\"id\":53,\"kind\":65536,\"name\":\"__type\",\"url\":\"classes/errors.ErrorAsyncLocksTimeout.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-class\",\"parent\":\"errors.ErrorAsyncLocksTimeout\"},{\"id\":54,\"kind\":512,\"name\":\"constructor\",\"url\":\"classes/errors.ErrorAsyncLocksTimeout.html#constructor\",\"classes\":\"tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorAsyncLocksTimeout\"},{\"id\":55,\"kind\":1024,\"name\":\"data\",\"url\":\"classes/errors.ErrorAsyncLocksTimeout.html#data\",\"classes\":\"tsd-kind-property tsd-parent-kind-class tsd-is-inherited\",\"parent\":\"errors.ErrorAsyncLocksTimeout\"},{\"id\":56,\"kind\":4194304,\"name\":\"POJO\",\"url\":\"modules.html#POJO\",\"classes\":\"tsd-kind-type-alias\"},{\"id\":57,\"kind\":65536,\"name\":\"__type\",\"url\":\"modules.html#POJO.__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-alias\",\"parent\":\"POJO\"}],\"index\":{\"version\":\"2.3.9\",\"fields\":[\"name\",\"parent\"],\"fieldVectors\":[[\"name/0\",[0,15.518]],[\"parent/0\",[]],[\"name/1\",[1,23.728]],[\"parent/1\",[0,1.482]],[\"name/2\",[2,36.721]],[\"parent/2\",[0,1.482]],[\"name/3\",[3,36.721]],[\"parent/3\",[0,1.482]],[\"name/4\",[0,15.518]],[\"parent/4\",[0,1.482]],[\"name/5\",[4,36.721]],[\"parent/5\",[0,1.482]],[\"name/6\",[5,28.248]],[\"parent/6\",[0,1.482]],[\"name/7\",[6,28.248]],[\"parent/7\",[0,1.482]],[\"name/8\",[7,36.721]],[\"parent/8\",[0,1.482]],[\"name/9\",[8,36.721]],[\"parent/9\",[0,1.482]],[\"name/10\",[9,12.742]],[\"parent/10\",[]],[\"name/11\",[1,23.728]],[\"parent/11\",[9,1.217]],[\"name/12\",[10,31.612]],[\"parent/12\",[9,1.217]],[\"name/13\",[11,31.612]],[\"parent/13\",[9,1.217]],[\"name/14\",[0,15.518]],[\"parent/14\",[9,1.217]],[\"name/15\",[12,36.721]],[\"parent/15\",[9,1.217]],[\"name/16\",[13,31.612]],[\"parent/16\",[9,1.217]],[\"name/17\",[14,31.612]],[\"parent/17\",[9,1.217]],[\"name/18\",[15,31.612]],[\"parent/18\",[9,1.217]],[\"name/19\",[16,31.612]],[\"parent/19\",[9,1.217]],[\"name/20\",[5,28.248]],[\"parent/20\",[9,1.217]],[\"name/21\",[6,28.248]],[\"parent/21\",[9,1.217]],[\"name/22\",[17,31.612]],[\"parent/22\",[9,1.217]],[\"name/23\",[18,31.612]],[\"parent/23\",[9,1.217]],[\"name/24\",[19,31.612]],[\"parent/24\",[9,1.217]],[\"name/25\",[20,31.612]],[\"parent/25\",[9,1.217]],[\"name/26\",[21,11.598]],[\"parent/26\",[]],[\"name/27\",[1,23.728]],[\"parent/27\",[21,1.107]],[\"name/28\",[22,36.721]],[\"parent/28\",[21,1.107]],[\"name/29\",[23,36.721]],[\"parent/29\",[21,1.107]],[\"name/30\",[24,36.721]],[\"parent/30\",[21,1.107]],[\"name/31\",[25,36.721]],[\"parent/31\",[21,1.107]],[\"name/32\",[10,31.612]],[\"parent/32\",[21,1.107]],[\"name/33\",[11,31.612]],[\"parent/33\",[21,1.107]],[\"name/34\",[13,31.612]],[\"parent/34\",[21,1.107]],[\"name/35\",[14,31.612]],[\"parent/35\",[21,1.107]],[\"name/36\",[15,31.612]],[\"parent/36\",[21,1.107]],[\"name/37\",[16,31.612]],[\"parent/37\",[21,1.107]],[\"name/38\",[5,28.248]],[\"parent/38\",[21,1.107]],[\"name/39\",[6,28.248]],[\"parent/39\",[21,1.107]],[\"name/40\",[17,31.612]],[\"parent/40\",[21,1.107]],[\"name/41\",[18,31.612]],[\"parent/41\",[21,1.107]],[\"name/42\",[19,31.612]],[\"parent/42\",[21,1.107]],[\"name/43\",[20,31.612]],[\"parent/43\",[21,1.107]],[\"name/44\",[26,28.248]],[\"parent/44\",[]],[\"name/45\",[27,36.721]],[\"parent/45\",[26,2.697]],[\"name/46\",[28,36.721]],[\"parent/46\",[26,2.697]],[\"name/47\",[29,28.248]],[\"parent/47\",[]],[\"name/48\",[30,36.721]],[\"parent/48\",[29,2.697]],[\"name/49\",[31,28.248]],[\"parent/49\",[32,2.697]],[\"name/50\",[1,23.728]],[\"parent/50\",[32,2.697]],[\"name/51\",[33,31.612]],[\"parent/51\",[32,2.697]],[\"name/52\",[34,36.721]],[\"parent/52\",[29,2.697]],[\"name/53\",[31,28.248]],[\"parent/53\",[35,2.697]],[\"name/54\",[1,23.728]],[\"parent/54\",[35,2.697]],[\"name/55\",[33,31.612]],[\"parent/55\",[35,2.697]],[\"name/56\",[36,31.612]],[\"parent/56\",[]],[\"name/57\",[31,28.248]],[\"parent/57\",[36,3.019]]],\"invertedIndex\":[[\"__type\",{\"_index\":31,\"name\":{\"49\":{},\"53\":{},\"57\":{}},\"parent\":{}}],[\"_count\",{\"_index\":3,\"name\":{\"3\":{}},\"parent\":{}}],[\"_lock\",{\"_index\":2,\"name\":{\"2\":{}},\"parent\":{}}],[\"_readercount\",{\"_index\":10,\"name\":{\"12\":{},\"32\":{}},\"parent\":{}}],[\"_writercount\",{\"_index\":11,\"name\":{\"13\":{},\"33\":{}},\"parent\":{}}],[\"constructor\",{\"_index\":1,\"name\":{\"1\":{},\"11\":{},\"27\":{},\"50\":{},\"54\":{}},\"parent\":{}}],[\"count\",{\"_index\":4,\"name\":{\"5\":{}},\"parent\":{}}],[\"data\",{\"_index\":33,\"name\":{\"51\":{},\"55\":{}},\"parent\":{}}],[\"errorasynclocks\",{\"_index\":30,\"name\":{\"48\":{}},\"parent\":{}}],[\"errorasynclockstimeout\",{\"_index\":34,\"name\":{\"52\":{}},\"parent\":{}}],[\"errors\",{\"_index\":29,\"name\":{\"47\":{}},\"parent\":{\"48\":{},\"52\":{}}}],[\"errors.errorasynclocks\",{\"_index\":32,\"name\":{},\"parent\":{\"49\":{},\"50\":{},\"51\":{}}}],[\"errors.errorasynclockstimeout\",{\"_index\":35,\"name\":{},\"parent\":{\"53\":{},\"54\":{},\"55\":{}}}],[\"islocked\",{\"_index\":5,\"name\":{\"6\":{},\"20\":{},\"38\":{}},\"parent\":{}}],[\"lock\",{\"_index\":0,\"name\":{\"0\":{},\"4\":{},\"14\":{}},\"parent\":{\"1\":{},\"2\":{},\"3\":{},\"4\":{},\"5\":{},\"6\":{},\"7\":{},\"8\":{},\"9\":{}}}],[\"pojo\",{\"_index\":36,\"name\":{\"56\":{}},\"parent\":{\"57\":{}}}],[\"read\",{\"_index\":13,\"name\":{\"16\":{},\"34\":{}},\"parent\":{}}],[\"readercount\",{\"_index\":15,\"name\":{\"18\":{},\"36\":{}},\"parent\":{}}],[\"readercountblocked\",{\"_index\":25,\"name\":{\"31\":{}},\"parent\":{}}],[\"readerslock\",{\"_index\":22,\"name\":{\"28\":{}},\"parent\":{}}],[\"readersrelease\",{\"_index\":24,\"name\":{\"30\":{}},\"parent\":{}}],[\"release\",{\"_index\":12,\"name\":{\"15\":{}},\"parent\":{}}],[\"rwlockreader\",{\"_index\":9,\"name\":{\"10\":{}},\"parent\":{\"11\":{},\"12\":{},\"13\":{},\"14\":{},\"15\":{},\"16\":{},\"17\":{},\"18\":{},\"19\":{},\"20\":{},\"21\":{},\"22\":{},\"23\":{},\"24\":{},\"25\":{}}}],[\"rwlockwriter\",{\"_index\":21,\"name\":{\"26\":{}},\"parent\":{\"27\":{},\"28\":{},\"29\":{},\"30\":{},\"31\":{},\"32\":{},\"33\":{},\"34\":{},\"35\":{},\"36\":{},\"37\":{},\"38\":{},\"39\":{},\"40\":{},\"41\":{},\"42\":{},\"43\":{}}}],[\"sleep\",{\"_index\":27,\"name\":{\"45\":{}},\"parent\":{}}],[\"utils\",{\"_index\":26,\"name\":{\"44\":{}},\"parent\":{\"45\":{},\"46\":{}}}],[\"waitforunlock\",{\"_index\":6,\"name\":{\"7\":{},\"21\":{},\"39\":{}},\"parent\":{}}],[\"withf\",{\"_index\":7,\"name\":{\"8\":{}},\"parent\":{}}],[\"withg\",{\"_index\":8,\"name\":{\"9\":{}},\"parent\":{}}],[\"withreadf\",{\"_index\":17,\"name\":{\"22\":{},\"40\":{}},\"parent\":{}}],[\"withreadg\",{\"_index\":19,\"name\":{\"24\":{},\"42\":{}},\"parent\":{}}],[\"withwritef\",{\"_index\":18,\"name\":{\"23\":{},\"41\":{}},\"parent\":{}}],[\"withwriteg\",{\"_index\":20,\"name\":{\"25\":{},\"43\":{}},\"parent\":{}}],[\"write\",{\"_index\":14,\"name\":{\"17\":{},\"35\":{}},\"parent\":{}}],[\"writercount\",{\"_index\":16,\"name\":{\"19\":{},\"37\":{}},\"parent\":{}}],[\"writerslock\",{\"_index\":23,\"name\":{\"29\":{}},\"parent\":{}}],[\"yieldmicro\",{\"_index\":28,\"name\":{\"46\":{}},\"parent\":{}}]],\"pipeline\":[]}}"); \ No newline at end of file diff --git a/docs/classes/Lock.html b/docs/classes/Lock.html index ba24e14..df25c53 100644 --- a/docs/classes/Lock.html +++ b/docs/classes/Lock.html @@ -1 +1 @@ -Lock | @matrixai/async-locks
Options
All
  • Public
  • Public/Protected
  • All
Menu

Hierarchy

  • Lock

Index

Constructors

Properties

_count: number = 0
acquire: ResourceAcquire<Lock> = ...
lock: Mutex = ...
release: Releaser

Accessors

  • get count(): number

Methods

  • isLocked(): boolean
  • waitForUnlock(): Promise<void>
  • withF<T>(f: (resources: [Lock]) => Promise<T>): Promise<T>
  • Type parameters

    • T

    Parameters

    • f: (resources: [Lock]) => Promise<T>
        • (resources: [Lock]): Promise<T>
        • Parameters

          Returns Promise<T>

    Returns Promise<T>

  • withG<T, TReturn, TNext>(g: (resources: [Lock]) => AsyncGenerator<T, TReturn, TNext>): AsyncGenerator<T, TReturn, TNext>
  • Type parameters

    • T

    • TReturn

    • TNext

    Parameters

    • g: (resources: [Lock]) => AsyncGenerator<T, TReturn, TNext>
        • (resources: [Lock]): AsyncGenerator<T, TReturn, TNext>
        • Parameters

          Returns AsyncGenerator<T, TReturn, TNext>

    Returns AsyncGenerator<T, TReturn, TNext>

Generated using TypeDoc

\ No newline at end of file +Lock | @matrixai/async-locks
Options
All
  • Public
  • Public/Protected
  • All
Menu

Hierarchy

  • Lock

Index

Constructors

Properties

_count: number = 0
_lock: Mutex = ...

Accessors

  • get count(): number

Methods

  • isLocked(): boolean
  • lock(timeout?: number): ResourceAcquire<Lock>
  • waitForUnlock(timeout?: number): Promise<void>
  • Parameters

    • Optional timeout: number

    Returns Promise<void>

  • withF<T>(f: (resources: [Lock]) => Promise<T>, timeout?: number): Promise<T>
  • Type parameters

    • T

    Parameters

    • f: (resources: [Lock]) => Promise<T>
        • (resources: [Lock]): Promise<T>
        • Parameters

          Returns Promise<T>

    • Optional timeout: number

    Returns Promise<T>

  • withG<T, TReturn, TNext>(g: (resources: [Lock]) => AsyncGenerator<T, TReturn, TNext>, timeout?: number): AsyncGenerator<T, TReturn, TNext>
  • Type parameters

    • T

    • TReturn

    • TNext

    Parameters

    • g: (resources: [Lock]) => AsyncGenerator<T, TReturn, TNext>
        • (resources: [Lock]): AsyncGenerator<T, TReturn, TNext>
        • Parameters

          Returns AsyncGenerator<T, TReturn, TNext>

    • Optional timeout: number

    Returns AsyncGenerator<T, TReturn, TNext>

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/classes/RWLockReader.html b/docs/classes/RWLockReader.html index eea713f..307fed6 100644 --- a/docs/classes/RWLockReader.html +++ b/docs/classes/RWLockReader.html @@ -1,3 +1,3 @@ RWLockReader | @matrixai/async-locks
Options
All
  • Public
  • Public/Protected
  • All
Menu

Read-preferring read write lock

-

Hierarchy

  • RWLockReader

Index

Constructors

Properties

_readerCount: number = 0
_writerCount: number = 0
acquireRead: ResourceAcquire<RWLockReader> = ...
acquireWrite: ResourceAcquire<RWLockReader> = ...
lock: Mutex = ...
release: Releaser

Accessors

  • get readerCount(): number
  • get writerCount(): number

Methods

  • isLocked(): boolean
  • waitForUnlock(): Promise<void>
  • withReadF<T>(f: (resources: [RWLockReader]) => Promise<T>): Promise<T>
  • withReadG<T, TReturn, TNext>(g: (resources: [RWLockReader]) => AsyncGenerator<T, TReturn, TNext>): AsyncGenerator<T, TReturn, TNext>
  • Type parameters

    • T

    • TReturn

    • TNext

    Parameters

    • g: (resources: [RWLockReader]) => AsyncGenerator<T, TReturn, TNext>
        • (resources: [RWLockReader]): AsyncGenerator<T, TReturn, TNext>
        • Parameters

          Returns AsyncGenerator<T, TReturn, TNext>

    Returns AsyncGenerator<T, TReturn, TNext>

  • withWriteF<T>(f: (resources: [RWLockReader]) => Promise<T>): Promise<T>
  • withWriteG<T, TReturn, TNext>(g: (resources: [RWLockReader]) => AsyncGenerator<T, TReturn, TNext>): AsyncGenerator<T, TReturn, TNext>
  • Type parameters

    • T

    • TReturn

    • TNext

    Parameters

    • g: (resources: [RWLockReader]) => AsyncGenerator<T, TReturn, TNext>
        • (resources: [RWLockReader]): AsyncGenerator<T, TReturn, TNext>
        • Parameters

          Returns AsyncGenerator<T, TReturn, TNext>

    Returns AsyncGenerator<T, TReturn, TNext>

Generated using TypeDoc

\ No newline at end of file +

Hierarchy

Index

Constructors

Properties

_readerCount: number = 0
_writerCount: number = 0
lock: Mutex = ...
release: Releaser

Accessors

Methods

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/classes/RWLockWriter.html b/docs/classes/RWLockWriter.html index 5da3d98..7ba33bf 100644 --- a/docs/classes/RWLockWriter.html +++ b/docs/classes/RWLockWriter.html @@ -1,3 +1,3 @@ RWLockWriter | @matrixai/async-locks
Options
All
  • Public
  • Public/Protected
  • All
Menu

Write-preferring read write lock

-

Hierarchy

  • RWLockWriter

Index

Constructors

Properties

_readerCount: number = 0
_writerCount: number = 0
acquireRead: ResourceAcquire<RWLockWriter> = ...
acquireWrite: ResourceAcquire<RWLockWriter> = ...
readerCountBlocked: number = 0
readersLock: Mutex = ...
readersRelease: Releaser
writersLock: Mutex = ...

Accessors

  • get readerCount(): number
  • get writerCount(): number

Methods

  • isLocked(): boolean
  • waitForUnlock(): Promise<void>
  • withReadF<T>(f: (resources: [RWLockWriter]) => Promise<T>): Promise<T>
  • withReadG<T, TReturn, TNext>(g: (resources: [RWLockWriter]) => AsyncGenerator<T, TReturn, TNext>): AsyncGenerator<T, TReturn, TNext>
  • Type parameters

    • T

    • TReturn

    • TNext

    Parameters

    • g: (resources: [RWLockWriter]) => AsyncGenerator<T, TReturn, TNext>
        • (resources: [RWLockWriter]): AsyncGenerator<T, TReturn, TNext>
        • Parameters

          Returns AsyncGenerator<T, TReturn, TNext>

    Returns AsyncGenerator<T, TReturn, TNext>

  • withWriteF<T>(f: (resources: [RWLockWriter]) => Promise<T>): Promise<T>
  • withWriteG<T, TReturn, TNext>(g: (resources: [RWLockWriter]) => AsyncGenerator<T, TReturn, TNext>): AsyncGenerator<T, TReturn, TNext>
  • Type parameters

    • T

    • TReturn

    • TNext

    Parameters

    • g: (resources: [RWLockWriter]) => AsyncGenerator<T, TReturn, TNext>
        • (resources: [RWLockWriter]): AsyncGenerator<T, TReturn, TNext>
        • Parameters

          Returns AsyncGenerator<T, TReturn, TNext>

    Returns AsyncGenerator<T, TReturn, TNext>

Generated using TypeDoc

\ No newline at end of file +

Hierarchy

Index

Constructors

Properties

_readerCount: number = 0
_writerCount: number = 0
readerCountBlocked: number = 0
readersLock: Mutex = ...
readersRelease: Releaser
writersLock: Mutex = ...

Accessors

Methods

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/classes/errors.ErrorAsyncLocks.html b/docs/classes/errors.ErrorAsyncLocks.html new file mode 100644 index 0000000..2d29fb6 --- /dev/null +++ b/docs/classes/errors.ErrorAsyncLocks.html @@ -0,0 +1,6 @@ +ErrorAsyncLocks | @matrixai/async-locks
Options
All
  • Public
  • Public/Protected
  • All
Menu

Hierarchy

Index

Constructors

Properties

data: POJO
message: string
name: string
stack?: string
prepareStackTrace?: (err: Error, stackTraces: CallSite[]) => any

Type declaration

stackTraceLimit: number

Methods

  • captureStackTrace(targetObject: object, constructorOpt?: Function): void
  • +

    Create .stack property on a target object

    +

    Parameters

    • targetObject: object
    • Optional constructorOpt: Function

    Returns void

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/classes/errors.ErrorAsyncLocksTimeout.html b/docs/classes/errors.ErrorAsyncLocksTimeout.html new file mode 100644 index 0000000..df11cf9 --- /dev/null +++ b/docs/classes/errors.ErrorAsyncLocksTimeout.html @@ -0,0 +1,6 @@ +ErrorAsyncLocksTimeout | @matrixai/async-locks
Options
All
  • Public
  • Public/Protected
  • All
Menu

Hierarchy

Index

Constructors

Properties

data: POJO
message: string
name: string
stack?: string
prepareStackTrace?: (err: Error, stackTraces: CallSite[]) => any

Type declaration

stackTraceLimit: number

Methods

  • captureStackTrace(targetObject: object, constructorOpt?: Function): void
  • +

    Create .stack property on a target object

    +

    Parameters

    • targetObject: object
    • Optional constructorOpt: Function

    Returns void

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/index.html b/docs/index.html index d2460fe..b38d7f7 100644 --- a/docs/index.html +++ b/docs/index.html @@ -30,4 +30,4 @@

Publishing

# npm login
npm version patch # major/minor/patch
npm run build
npm publish --access public
git push
git push --tags
-

Generated using TypeDoc

\ No newline at end of file +

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/modules.html b/docs/modules.html index 7ac2560..ff863a6 100644 --- a/docs/modules.html +++ b/docs/modules.html @@ -1 +1,3 @@ -@matrixai/async-locks
Options
All
  • Public
  • Public/Protected
  • All
Menu

@matrixai/async-locks

Generated using TypeDoc

\ No newline at end of file +@matrixai/async-locks
Options
All
  • Public
  • Public/Protected
  • All
Menu

@matrixai/async-locks

Index

Namespaces

Classes

Type aliases

Type aliases

POJO: {}
+

Plain data dictionary

+

Type declaration

  • [key: string]: any

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/modules/errors.html b/docs/modules/errors.html new file mode 100644 index 0000000..16cfd72 --- /dev/null +++ b/docs/modules/errors.html @@ -0,0 +1 @@ +errors | @matrixai/async-locks
Options
All
  • Public
  • Public/Protected
  • All
Menu

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/modules/utils.html b/docs/modules/utils.html new file mode 100644 index 0000000..3222105 --- /dev/null +++ b/docs/modules/utils.html @@ -0,0 +1 @@ +utils | @matrixai/async-locks
Options
All
  • Public
  • Public/Protected
  • All
Menu

Index

Functions

  • sleep(ms: number): Promise<void>
  • yieldMicro(): Promise<void>

Generated using TypeDoc

\ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 4afeddd..4ac7427 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4337,6 +4337,11 @@ "punycode": "^2.1.1" } }, + "ts-custom-error": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.2.0.tgz", + "integrity": "sha512-cBvC2QjtvJ9JfWLvstVnI45Y46Y5dMxIaG1TDMGAD/R87hpvqFL+7LhvUDhnRCfOnx/xitollFWWvUKKKhbN0A==" + }, "ts-jest": { "version": "27.0.7", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.7.tgz", diff --git a/package.json b/package.json index 83ee82f..1d65106 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ }, "dependencies": { "@matrixai/resources": "^1.0.0", - "async-mutex": "^0.3.2" + "async-mutex": "^0.3.2", + "ts-custom-error": "^3.2.0" }, "devDependencies": { "@types/jest": "^27.0.2", diff --git a/src/Lock.ts b/src/Lock.ts index d419151..2e411b9 100644 --- a/src/Lock.ts +++ b/src/Lock.ts @@ -1,45 +1,77 @@ import type { MutexInterface } from 'async-mutex'; import type { ResourceAcquire } from '@matrixai/resources'; -import { Mutex } from 'async-mutex'; +import { Mutex, withTimeout } from 'async-mutex'; import { withF, withG } from '@matrixai/resources'; +import { sleep, yieldMicro } from './utils'; +import { ErrorAsyncLocksTimeout } from './errors'; class Lock { - protected lock: Mutex = new Mutex(); - protected release: MutexInterface.Releaser; + protected _lock: Mutex = new Mutex(); protected _count: number = 0; - public acquire: ResourceAcquire = async () => { - ++this._count; - this.release = await this.lock.acquire(); - return [ - async () => { + public lock(timeout?: number): ResourceAcquire { + return async () => { + ++this._count; + let lock: MutexInterface = this._lock; + if (timeout != null) { + lock = withTimeout(this._lock, timeout, new ErrorAsyncLocksTimeout()); + } + let release: MutexInterface.Releaser; + try { + release = await lock.acquire(); + } catch (e) { --this._count; - this.release(); - }, - this, - ]; - }; + throw e; + } + return [ + async () => { + --this._count; + release(); + // Allow semaphore to settle https://github.com/DirtyHairy/async-mutex/issues/54 + await yieldMicro(); + }, + this, + ]; + }; + } public get count(): number { return this._count; } public isLocked(): boolean { - return this.lock.isLocked(); + return this._lock.isLocked(); } - public async waitForUnlock(): Promise { - return this.lock.waitForUnlock(); + public async waitForUnlock(timeout?: number): Promise { + if (timeout != null) { + let timedOut = false; + await Promise.race([ + this._lock.waitForUnlock(), + sleep(timeout).then(() => { + timedOut = true; + }), + ]); + if (timedOut) { + throw new ErrorAsyncLocksTimeout(); + } + } else { + await this._lock.waitForUnlock(); + } } - public async withF(f: (resources: [Lock]) => Promise): Promise { - return withF([this.acquire], f); + public async withF( + f: (resources: [Lock]) => Promise, + timeout?: number, + ): Promise { + return withF([this.lock(timeout)], f); } public withG( g: (resources: [Lock]) => AsyncGenerator, + timeout?: number, ): AsyncGenerator { - return withG([this.acquire], g); + return withG([this.lock(timeout)], g); } } diff --git a/src/RWLockReader.ts b/src/RWLockReader.ts index 561a845..3434de8 100644 --- a/src/RWLockReader.ts +++ b/src/RWLockReader.ts @@ -1,7 +1,9 @@ import type { MutexInterface } from 'async-mutex'; import type { ResourceAcquire } from '@matrixai/resources'; -import { Mutex } from 'async-mutex'; +import { Mutex, withTimeout } from 'async-mutex'; import { withF, withG } from '@matrixai/resources'; +import { sleep, yieldMicro } from './utils'; +import { ErrorAsyncLocksTimeout } from './errors'; /** * Read-preferring read write lock @@ -12,35 +14,65 @@ class RWLockReader { protected lock: Mutex = new Mutex(); protected release: MutexInterface.Releaser; - public acquireRead: ResourceAcquire = async () => { - const readerCount = ++this._readerCount; - // The first reader locks - if (readerCount === 1) { - this.release = await this.lock.acquire(); - } - return [ - async () => { - const readerCount = --this._readerCount; - // The last reader unlocks - if (readerCount === 0) { - this.release(); + public read(timeout?: number): ResourceAcquire { + return async () => { + const readerCount = ++this._readerCount; + // The first reader locks + if (readerCount === 1) { + let lock: MutexInterface = this.lock; + if (timeout != null) { + lock = withTimeout(this.lock, timeout, new ErrorAsyncLocksTimeout()); + } + try { + this.release = await lock.acquire(); + } catch (e) { + --this._readerCount; + throw e; } - }, - this, - ]; - }; + } else { + // Yield for the first reader to finish locking + await yieldMicro(); + } + return [ + async () => { + const readerCount = --this._readerCount; + // The last reader unlocks + if (readerCount === 0) { + this.release(); + } + // Allow semaphore to settle https://github.com/DirtyHairy/async-mutex/issues/54 + await yieldMicro(); + }, + this, + ]; + }; + } - public acquireWrite: ResourceAcquire = async () => { - ++this._writerCount; - this.release = await this.lock.acquire(); - return [ - async () => { + public write(timeout?: number): ResourceAcquire { + return async () => { + ++this._writerCount; + let lock: MutexInterface = this.lock; + if (timeout != null) { + lock = withTimeout(this.lock, timeout, new ErrorAsyncLocksTimeout()); + } + let release: MutexInterface.Releaser; + try { + release = await lock.acquire(); + } catch (e) { --this._writerCount; - this.release(); - }, - this, - ]; - }; + throw e; + } + return [ + async () => { + release(); + --this._writerCount; + // Allow semaphore to settle https://github.com/DirtyHairy/async-mutex/issues/54 + await yieldMicro(); + }, + this, + ]; + }; + } public get readerCount(): number { return this._readerCount; @@ -54,32 +86,49 @@ class RWLockReader { return this.lock.isLocked(); } - public async waitForUnlock(): Promise { - return this.lock.waitForUnlock(); + public async waitForUnlock(timeout?: number): Promise { + if (timeout != null) { + let timedOut = false; + await Promise.race([ + this.lock.waitForUnlock(), + sleep(timeout).then(() => { + timedOut = true; + }), + ]); + if (timedOut) { + throw new ErrorAsyncLocksTimeout(); + } + } else { + await this.lock.waitForUnlock(); + } } public async withReadF( f: (resources: [RWLockReader]) => Promise, + timeout?: number, ): Promise { - return withF([this.acquireRead], f); + return withF([this.read(timeout)], f); } public async withWriteF( f: (resources: [RWLockReader]) => Promise, + timeout?: number, ): Promise { - return withF([this.acquireWrite], f); + return withF([this.write(timeout)], f); } public withReadG( g: (resources: [RWLockReader]) => AsyncGenerator, + timeout?: number, ): AsyncGenerator { - return withG([this.acquireRead], g); + return withG([this.read(timeout)], g); } public withWriteG( g: (resources: [RWLockReader]) => AsyncGenerator, + timeout?: number, ): AsyncGenerator { - return withG([this.acquireWrite], g); + return withG([this.write(timeout)], g); } } diff --git a/src/RWLockWriter.ts b/src/RWLockWriter.ts index a7bcd3a..96367e2 100644 --- a/src/RWLockWriter.ts +++ b/src/RWLockWriter.ts @@ -1,7 +1,10 @@ import type { MutexInterface } from 'async-mutex'; import type { ResourceAcquire } from '@matrixai/resources'; -import { Mutex } from 'async-mutex'; +import { performance } from 'perf_hooks'; +import { Mutex, withTimeout } from 'async-mutex'; import { withF, withG } from '@matrixai/resources'; +import { sleep, yieldMicro } from './utils'; +import { ErrorAsyncLocksTimeout } from './errors'; /** * Write-preferring read write lock @@ -14,42 +17,114 @@ class RWLockWriter { protected _readerCount: number = 0; protected _writerCount: number = 0; - public acquireRead: ResourceAcquire = async () => { - if (this._writerCount > 0) { - ++this.readerCountBlocked; - await this.writersLock.waitForUnlock(); - --this.readerCountBlocked; - } - const readerCount = ++this._readerCount; - // The first reader locks - if (readerCount === 1) { - this.readersRelease = await this.readersLock.acquire(); - } - return [ - async () => { - const readerCount = --this._readerCount; - // The last reader unlocks - if (readerCount === 0) { - this.readersRelease(); + public read(timeout?: number): ResourceAcquire { + return async () => { + const t1 = performance.now(); + if (this._writerCount > 0) { + ++this.readerCountBlocked; + if (timeout != null) { + let timedOut = false; + await Promise.race([ + this.writersLock.waitForUnlock(), + sleep(timeout).then(() => { + timedOut = true; + }), + ]); + if (timedOut) { + --this.readerCountBlocked; + throw new ErrorAsyncLocksTimeout(); + } + } else { + await this.writersLock.waitForUnlock(); + } + --this.readerCountBlocked; + } + const readerCount = ++this._readerCount; + // The first reader locks + if (readerCount === 1) { + let readersLock: MutexInterface = this.readersLock; + if (timeout != null) { + timeout = timeout - (performance.now() - t1); + readersLock = withTimeout( + this.readersLock, + timeout, + new ErrorAsyncLocksTimeout(), + ); + } + try { + this.readersRelease = await readersLock.acquire(); + } catch (e) { + --this._readerCount; + throw e; } - }, - this, - ]; - }; + } else { + // Yield for the first reader to finish locking + await yieldMicro(); + } + return [ + async () => { + const readerCount = --this._readerCount; + // The last reader unlocks + if (readerCount === 0) { + this.readersRelease(); + // Allow semaphore to settle https://github.com/DirtyHairy/async-mutex/issues/54 + await yieldMicro(); + } + }, + this, + ]; + }; + } - public acquireWrite: ResourceAcquire = async () => { - ++this._writerCount; - const writersRelease = await this.writersLock.acquire(); - this.readersRelease = await this.readersLock.acquire(); - return [ - async () => { - this.readersRelease(); + public write(timeout?: number): ResourceAcquire { + return async () => { + ++this._writerCount; + let writersLock: MutexInterface = this.writersLock; + if (timeout != null) { + writersLock = withTimeout( + this.writersLock, + timeout, + new ErrorAsyncLocksTimeout(), + ); + } + const t1 = performance.now(); + let writersRelease: MutexInterface.Releaser; + try { + writersRelease = await writersLock.acquire(); + } catch (e) { + --this._writerCount; + throw e; + } + let readersLock: MutexInterface = this.readersLock; + if (timeout != null) { + timeout = timeout - (performance.now() - t1); + readersLock = withTimeout( + this.readersLock, + timeout, + new ErrorAsyncLocksTimeout(), + ); + } + try { + this.readersRelease = await readersLock.acquire(); + } catch (e) { writersRelease(); --this._writerCount; - }, - this, - ]; - }; + // Allow semaphore to settle https://github.com/DirtyHairy/async-mutex/issues/54 + await yieldMicro(); + throw e; + } + return [ + async () => { + this.readersRelease(); + writersRelease(); + --this._writerCount; + // Allow semaphore to settle https://github.com/DirtyHairy/async-mutex/issues/54 + await yieldMicro(); + }, + this, + ]; + }; + } public get readerCount(): number { return this._readerCount + this.readerCountBlocked; @@ -63,36 +138,55 @@ class RWLockWriter { return this.readersLock.isLocked() || this.writersLock.isLocked(); } - public async waitForUnlock(): Promise { - await Promise.all([ - this.readersLock.waitForUnlock(), - this.writersLock.waitForUnlock(), - ]); - return; + public async waitForUnlock(timeout?: number): Promise { + if (timeout != null) { + let timedOut = false; + await Promise.race([ + Promise.all([ + this.readersLock.waitForUnlock(), + this.writersLock.waitForUnlock(), + ]), + sleep(timeout).then(() => { + timedOut = true; + }), + ]); + if (timedOut) { + throw new ErrorAsyncLocksTimeout(); + } + } else { + await Promise.all([ + this.readersLock.waitForUnlock(), + this.writersLock.waitForUnlock(), + ]); + } } public async withReadF( f: (resources: [RWLockWriter]) => Promise, + timeout?: number, ): Promise { - return withF([this.acquireRead], f); + return withF([this.read(timeout)], f); } public async withWriteF( f: (resources: [RWLockWriter]) => Promise, + timeout?: number, ): Promise { - return withF([this.acquireWrite], f); + return withF([this.write(timeout)], f); } public withReadG( g: (resources: [RWLockWriter]) => AsyncGenerator, + timeout?: number, ): AsyncGenerator { - return withG([this.acquireRead], g); + return withG([this.read(timeout)], g); } public withWriteG( g: (resources: [RWLockWriter]) => AsyncGenerator, + timeout?: number, ): AsyncGenerator { - return withG([this.acquireWrite], g); + return withG([this.write(timeout)], g); } } diff --git a/src/errors.ts b/src/errors.ts new file mode 100644 index 0000000..1e8e9e8 --- /dev/null +++ b/src/errors.ts @@ -0,0 +1,15 @@ +import type { POJO } from './types'; + +import { CustomError } from 'ts-custom-error'; + +class ErrorAsyncLocks extends CustomError { + data: POJO; + constructor(message: string = '', data: POJO = {}) { + super(message); + this.data = data; + } +} + +class ErrorAsyncLocksTimeout extends ErrorAsyncLocks {} + +export { ErrorAsyncLocks, ErrorAsyncLocksTimeout }; diff --git a/src/index.ts b/src/index.ts index cf26ea2..160836f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,6 @@ export { default as Lock } from './Lock'; export { default as RWLockReader } from './RWLockReader'; export { default as RWLockWriter } from './RWLockWriter'; +export * as utils from './utils'; +export * as errors from './errors'; +export * from './types'; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..7995e54 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,6 @@ +/** + * Plain data dictionary + */ +type POJO = { [key: string]: any }; + +export type { POJO }; diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..094d0ee --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,9 @@ +async function sleep(ms: number): Promise { + return await new Promise((r) => setTimeout(r, ms)); +} + +async function yieldMicro(): Promise { + return await new Promise((r) => queueMicrotask(r)); +} + +export { sleep, yieldMicro }; diff --git a/tests/Lock.test.ts b/tests/Lock.test.ts index 45e534c..c174c8e 100644 --- a/tests/Lock.test.ts +++ b/tests/Lock.test.ts @@ -1,11 +1,12 @@ import { withF, withG } from '@matrixai/resources'; import Lock from '@/Lock'; -import * as testUtils from './utils'; +import * as utils from '@/utils'; +import * as errors from '@/errors'; describe(Lock.name, () => { test('withF', async () => { const lock = new Lock(); - const p = withF([lock.acquire], async ([lock]) => { + const p = withF([lock.lock()], async ([lock]) => { expect(lock.isLocked()).toBe(true); expect(lock.count).toBe(1); }); @@ -17,7 +18,7 @@ describe(Lock.name, () => { }); test('withG', async () => { const lock = new Lock(); - const g1 = withG([lock.acquire], async function* ([lock]): AsyncGenerator< + const g1 = withG([lock.lock()], async function* ([lock]): AsyncGenerator< string, string, void @@ -48,7 +49,7 @@ describe(Lock.name, () => { expect(lock.isLocked()).toBe(false); expect(lock.count).toBe(0); // To actually get the value use while loop or explicit `next()` - const g2 = withG([lock.acquire], async function* (): AsyncGenerator< + const g2 = withG([lock.lock()], async function* (): AsyncGenerator< string, string, void @@ -94,9 +95,9 @@ describe(Lock.name, () => { test('wait for unlock', async () => { const lock = new Lock(); let value; - const p1 = withF([lock.acquire], async () => { + const p1 = withF([lock.lock()], async () => { value = 'p1'; - await testUtils.sleep(100); + await utils.sleep(100); }); const p2 = lock.waitForUnlock().then(() => { value = 'p2'; @@ -123,12 +124,12 @@ describe(Lock.name, () => { await Promise.all([ lock.withF(async () => { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; }), lock.withF(async () => { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; }), ]); @@ -138,7 +139,7 @@ describe(Lock.name, () => { (async () => { const g = lock.withG(async function* (): AsyncGenerator { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; return 'last'; }); @@ -148,7 +149,7 @@ describe(Lock.name, () => { (async () => { const g = lock.withG(async function* (): AsyncGenerator { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; return 'last'; }); @@ -158,4 +159,57 @@ describe(Lock.name, () => { ]); expect(value).toBe(2); }); + test('timeout', async () => { + const lock = new Lock(); + await withF([lock.lock(0)], async ([lock]) => { + expect(lock.isLocked()).toBe(true); + expect(lock.count).toBe(1); + const f = jest.fn(); + await expect(withF([lock.lock(100)], f)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + expect(f).not.toBeCalled(); + expect(lock.isLocked()).toBe(true); + expect(lock.count).toBe(1); + }); + expect(lock.isLocked()).toBe(false); + expect(lock.count).toBe(0); + await lock.withF(async () => { + const f = jest.fn(); + await expect(lock.withF(f, 100)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + expect(f).not.toBeCalled(); + }, 100); + const g = lock.withG(async function* () { + expect(lock.isLocked()).toBe(true); + expect(lock.count).toBe(1); + const f = jest.fn(); + const g = lock.withG(f, 100); + await expect(g.next()).rejects.toThrow(errors.ErrorAsyncLocksTimeout); + expect(f).not.toBeCalled(); + expect(lock.isLocked()).toBe(true); + expect(lock.count).toBe(1); + }, 100); + await g.next(); + expect(lock.isLocked()).toBe(false); + expect(lock.count).toBe(0); + }); + test('timeout waiting for unlock', async () => { + const lock = new Lock(); + await lock.waitForUnlock(100); + await withF([lock.lock()], async ([lock]) => { + await expect(lock.waitForUnlock(100)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + }); + await lock.waitForUnlock(100); + const g = withG([lock.lock()], async function* ([lock]) { + await expect(lock.waitForUnlock(100)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + }); + await g.next(); + await lock.waitForUnlock(100); + }); }); diff --git a/tests/RWLockReader.test.ts b/tests/RWLockReader.test.ts index 5c6b404..db07669 100644 --- a/tests/RWLockReader.test.ts +++ b/tests/RWLockReader.test.ts @@ -1,11 +1,12 @@ import { withF, withG } from '@matrixai/resources'; import RWLockReader from '@/RWLockReader'; -import * as testUtils from './utils'; +import * as utils from '@/utils'; +import * as errors from '@/errors'; describe(RWLockReader.name, () => { test('withF', async () => { const lock = new RWLockReader(); - const p1 = withF([lock.acquireRead], async ([lock]) => { + const p1 = withF([lock.read()], async ([lock]) => { expect(lock.isLocked()).toBe(true); expect(lock.readerCount).toBe(1); expect(lock.writerCount).toBe(0); @@ -17,7 +18,7 @@ describe(RWLockReader.name, () => { expect(lock.isLocked()).toBe(false); expect(lock.readerCount).toBe(0); expect(lock.writerCount).toBe(0); - const p2 = withF([lock.acquireWrite], async ([lock]) => { + const p2 = withF([lock.write()], async ([lock]) => { expect(lock.isLocked()).toBe(true); expect(lock.readerCount).toBe(0); expect(lock.writerCount).toBe(1); @@ -32,23 +33,24 @@ describe(RWLockReader.name, () => { }); test('withG on read', async () => { const lock = new RWLockReader(); - const g1 = withG( - [lock.acquireRead], - async function* ([lock]): AsyncGenerator { - expect(lock.isLocked()).toBe(true); - expect(lock.readerCount).toBe(1); - expect(lock.writerCount).toBe(0); - yield 'first'; - expect(lock.isLocked()).toBe(true); - expect(lock.readerCount).toBe(1); - expect(lock.writerCount).toBe(0); - yield 'second'; - expect(lock.isLocked()).toBe(true); - expect(lock.readerCount).toBe(1); - expect(lock.writerCount).toBe(0); - return 'last'; - }, - ); + const g1 = withG([lock.read()], async function* ([lock]): AsyncGenerator< + string, + string, + void + > { + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(1); + expect(lock.writerCount).toBe(0); + yield 'first'; + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(1); + expect(lock.writerCount).toBe(0); + yield 'second'; + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(1); + expect(lock.writerCount).toBe(0); + return 'last'; + }); for await (const _ of g1) { // It should be locked during iteration expect(lock.isLocked()).toBe(true); @@ -65,7 +67,7 @@ describe(RWLockReader.name, () => { expect(lock.readerCount).toBe(0); expect(lock.writerCount).toBe(0); // To actually get the value use while loop or explicit `next()` - const g2 = withG([lock.acquireRead], async function* (): AsyncGenerator< + const g2 = withG([lock.read()], async function* (): AsyncGenerator< string, string, void @@ -106,23 +108,24 @@ describe(RWLockReader.name, () => { }); test('withG on write', async () => { const lock = new RWLockReader(); - const g1 = withG( - [lock.acquireWrite], - async function* ([lock]): AsyncGenerator { - expect(lock.isLocked()).toBe(true); - expect(lock.readerCount).toBe(0); - expect(lock.writerCount).toBe(1); - yield 'first'; - expect(lock.isLocked()).toBe(true); - expect(lock.readerCount).toBe(0); - expect(lock.writerCount).toBe(1); - yield 'second'; - expect(lock.isLocked()).toBe(true); - expect(lock.readerCount).toBe(0); - expect(lock.writerCount).toBe(1); - return 'last'; - }, - ); + const g1 = withG([lock.write()], async function* ([lock]): AsyncGenerator< + string, + string, + void + > { + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(1); + yield 'first'; + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(1); + yield 'second'; + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(1); + return 'last'; + }); for await (const _ of g1) { // It should be locked during iteration expect(lock.isLocked()).toBe(true); @@ -130,7 +133,7 @@ describe(RWLockReader.name, () => { expect(lock.writerCount).toBe(1); } // To actually get the value use while loop or explicit `next()` - const g2 = withG([lock.acquireWrite], async function* (): AsyncGenerator< + const g2 = withG([lock.write()], async function* (): AsyncGenerator< string, string, void @@ -186,9 +189,9 @@ describe(RWLockReader.name, () => { test('wait for unlock on read', async () => { const lock = new RWLockReader(); let value; - const p1 = withF([lock.acquireRead], async () => { + const p1 = withF([lock.read()], async () => { value = 'p1'; - await testUtils.sleep(100); + await utils.sleep(100); }); const p2 = lock.waitForUnlock().then(() => { value = 'p2'; @@ -200,9 +203,9 @@ describe(RWLockReader.name, () => { test('wait for unlock on write', async () => { const lock = new RWLockReader(); let value; - const p1 = withF([lock.acquireWrite], async () => { + const p1 = withF([lock.write()], async () => { value = 'p1'; - await testUtils.sleep(100); + await utils.sleep(100); }); const p2 = lock.waitForUnlock().then(() => { value = 'p2'; @@ -238,12 +241,12 @@ describe(RWLockReader.name, () => { await Promise.all([ lock.withReadF(async () => { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; }), lock.withReadF(async () => { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; }), ]); @@ -252,12 +255,12 @@ describe(RWLockReader.name, () => { await Promise.all([ lock.withWriteF(async () => { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; }), lock.withWriteF(async () => { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; }), ]); @@ -267,7 +270,7 @@ describe(RWLockReader.name, () => { (async () => { const g = lock.withReadG(async function* (): AsyncGenerator { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; return 'last'; }); @@ -277,7 +280,7 @@ describe(RWLockReader.name, () => { (async () => { const g = lock.withReadG(async function* (): AsyncGenerator { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; return 'last'; }); @@ -291,7 +294,7 @@ describe(RWLockReader.name, () => { (async () => { const g = lock.withWriteG(async function* (): AsyncGenerator { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; return 'last'; }); @@ -301,7 +304,7 @@ describe(RWLockReader.name, () => { (async () => { const g = lock.withWriteG(async function* (): AsyncGenerator { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; return 'last'; }); @@ -312,7 +315,7 @@ describe(RWLockReader.name, () => { expect(value).toBe(2); }); test('order of operations', async () => { - // Write-preferring order + // Read-preferring order const lock = new RWLockReader(); const order: Array = []; const p1 = lock.withReadF(async () => { @@ -339,15 +342,122 @@ describe(RWLockReader.name, () => { await p4; await p5; await p6; - // Notice that `read2` happens first - // This can chnage if `read2` takes longer to do expect(order).toStrictEqual([ + 'read1', 'read2', 'read3', 'read4', - 'read1', 'write1', 'write2', ]); }); + test('timeout', async () => { + const lock = new RWLockReader(); + await withF([lock.read(0)], async ([lock]) => { + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(1); + expect(lock.writerCount).toBe(0); + const f = jest.fn(); + await expect(withF([lock.write(100)], f)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + expect(f).not.toBeCalled(); + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(1); + expect(lock.writerCount).toBe(0); + }); + expect(lock.isLocked()).toBe(false); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(0); + await withF([lock.write(0)], async ([lock]) => { + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(1); + const f = jest.fn(); + await expect(withF([lock.read(100)], f)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + expect(f).not.toBeCalled(); + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(1); + }); + await lock.withReadF(async () => { + const f = jest.fn(); + await expect(lock.withWriteF(f, 100)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + expect(f).not.toBeCalled(); + }, 100); + await lock.withWriteF(async () => { + const f = jest.fn(); + await expect(lock.withReadF(f, 100)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + expect(f).not.toBeCalled(); + }, 100); + await lock.withWriteF(async () => { + const f = jest.fn(); + await expect(lock.withWriteF(f, 100)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + expect(f).not.toBeCalled(); + }, 100); + const gRead = lock.withReadG(async function* () { + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(1); + expect(lock.writerCount).toBe(0); + const f = jest.fn(); + const g = lock.withWriteG(f, 100); + await expect(g.next()).rejects.toThrow(errors.ErrorAsyncLocksTimeout); + expect(f).not.toBeCalled(); + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(1); + expect(lock.writerCount).toBe(0); + }); + await gRead.next(); + expect(lock.isLocked()).toBe(false); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(0); + const gWrite = lock.withWriteG(async function* () { + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(1); + const f1 = jest.fn(); + const g1 = lock.withReadG(f1, 100); + await expect(g1.next()).rejects.toThrow(errors.ErrorAsyncLocksTimeout); + expect(f1).not.toBeCalled(); + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(1); + const f2 = jest.fn(); + const g2 = lock.withWriteG(f2, 100); + await expect(g2.next()).rejects.toThrow(errors.ErrorAsyncLocksTimeout); + expect(f2).not.toBeCalled(); + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(1); + }); + await gWrite.next(); + expect(lock.isLocked()).toBe(false); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(0); + }); + test('timeout waiting for unlock', async () => { + const lock = new RWLockReader(); + await lock.waitForUnlock(100); + await withF([lock.read()], async ([lock]) => { + await expect(lock.waitForUnlock(100)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + }); + await lock.waitForUnlock(100); + const g = withG([lock.write()], async function* ([lock]) { + await expect(lock.waitForUnlock(100)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + }); + await g.next(); + await lock.waitForUnlock(100); + }); }); diff --git a/tests/RWLockWriter.test.ts b/tests/RWLockWriter.test.ts index 0e759be..f1bae6f 100644 --- a/tests/RWLockWriter.test.ts +++ b/tests/RWLockWriter.test.ts @@ -1,11 +1,12 @@ import { withF, withG } from '@matrixai/resources'; import RWLockWriter from '@/RWLockWriter'; -import * as testUtils from './utils'; +import * as utils from '@/utils'; +import * as errors from '@/errors'; describe(RWLockWriter.name, () => { test('withF', async () => { const lock = new RWLockWriter(); - const p1 = withF([lock.acquireRead], async ([lock]) => { + const p1 = withF([lock.read()], async ([lock]) => { expect(lock.isLocked()).toBe(true); expect(lock.readerCount).toBe(1); expect(lock.writerCount).toBe(0); @@ -17,7 +18,7 @@ describe(RWLockWriter.name, () => { expect(lock.isLocked()).toBe(false); expect(lock.readerCount).toBe(0); expect(lock.writerCount).toBe(0); - const p2 = withF([lock.acquireWrite], async ([lock]) => { + const p2 = withF([lock.write()], async ([lock]) => { expect(lock.isLocked()).toBe(true); expect(lock.readerCount).toBe(0); expect(lock.writerCount).toBe(1); @@ -32,23 +33,24 @@ describe(RWLockWriter.name, () => { }); test('withG on read', async () => { const lock = new RWLockWriter(); - const g1 = withG( - [lock.acquireRead], - async function* ([lock]): AsyncGenerator { - expect(lock.isLocked()).toBe(true); - expect(lock.readerCount).toBe(1); - expect(lock.writerCount).toBe(0); - yield 'first'; - expect(lock.isLocked()).toBe(true); - expect(lock.readerCount).toBe(1); - expect(lock.writerCount).toBe(0); - yield 'second'; - expect(lock.isLocked()).toBe(true); - expect(lock.readerCount).toBe(1); - expect(lock.writerCount).toBe(0); - return 'last'; - }, - ); + const g1 = withG([lock.read()], async function* ([lock]): AsyncGenerator< + string, + string, + void + > { + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(1); + expect(lock.writerCount).toBe(0); + yield 'first'; + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(1); + expect(lock.writerCount).toBe(0); + yield 'second'; + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(1); + expect(lock.writerCount).toBe(0); + return 'last'; + }); for await (const _ of g1) { // It should be locked during iteration expect(lock.isLocked()).toBe(true); @@ -65,7 +67,7 @@ describe(RWLockWriter.name, () => { expect(lock.readerCount).toBe(0); expect(lock.writerCount).toBe(0); // To actually get the value use while loop or explicit `next()` - const g2 = withG([lock.acquireRead], async function* (): AsyncGenerator< + const g2 = withG([lock.read()], async function* (): AsyncGenerator< string, string, void @@ -106,23 +108,24 @@ describe(RWLockWriter.name, () => { }); test('withG on write', async () => { const lock = new RWLockWriter(); - const g1 = withG( - [lock.acquireWrite], - async function* ([lock]): AsyncGenerator { - expect(lock.isLocked()).toBe(true); - expect(lock.readerCount).toBe(0); - expect(lock.writerCount).toBe(1); - yield 'first'; - expect(lock.isLocked()).toBe(true); - expect(lock.readerCount).toBe(0); - expect(lock.writerCount).toBe(1); - yield 'second'; - expect(lock.isLocked()).toBe(true); - expect(lock.readerCount).toBe(0); - expect(lock.writerCount).toBe(1); - return 'last'; - }, - ); + const g1 = withG([lock.write()], async function* ([lock]): AsyncGenerator< + string, + string, + void + > { + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(1); + yield 'first'; + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(1); + yield 'second'; + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(1); + return 'last'; + }); for await (const _ of g1) { // It should be locked during iteration expect(lock.isLocked()).toBe(true); @@ -130,7 +133,7 @@ describe(RWLockWriter.name, () => { expect(lock.writerCount).toBe(1); } // To actually get the value use while loop or explicit `next()` - const g2 = withG([lock.acquireWrite], async function* (): AsyncGenerator< + const g2 = withG([lock.write()], async function* (): AsyncGenerator< string, string, void @@ -186,9 +189,9 @@ describe(RWLockWriter.name, () => { test('wait for unlock on read', async () => { const lock = new RWLockWriter(); let value; - const p1 = withF([lock.acquireRead], async () => { + const p1 = withF([lock.read()], async () => { value = 'p1'; - await testUtils.sleep(100); + await utils.sleep(100); }); const p2 = lock.waitForUnlock().then(() => { value = 'p2'; @@ -200,9 +203,9 @@ describe(RWLockWriter.name, () => { test('wait for unlock on write', async () => { const lock = new RWLockWriter(); let value; - const p1 = withF([lock.acquireWrite], async () => { + const p1 = withF([lock.write()], async () => { value = 'p1'; - await testUtils.sleep(100); + await utils.sleep(100); }); const p2 = lock.waitForUnlock().then(() => { value = 'p2'; @@ -238,12 +241,12 @@ describe(RWLockWriter.name, () => { await Promise.all([ lock.withReadF(async () => { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; }), lock.withReadF(async () => { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; }), ]); @@ -252,12 +255,12 @@ describe(RWLockWriter.name, () => { await Promise.all([ lock.withWriteF(async () => { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; }), lock.withWriteF(async () => { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; }), ]); @@ -267,7 +270,7 @@ describe(RWLockWriter.name, () => { (async () => { const g = lock.withReadG(async function* (): AsyncGenerator { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; return 'last'; }); @@ -277,7 +280,7 @@ describe(RWLockWriter.name, () => { (async () => { const g = lock.withReadG(async function* (): AsyncGenerator { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; return 'last'; }); @@ -291,7 +294,7 @@ describe(RWLockWriter.name, () => { (async () => { const g = lock.withWriteG(async function* (): AsyncGenerator { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; return 'last'; }); @@ -301,7 +304,7 @@ describe(RWLockWriter.name, () => { (async () => { const g = lock.withWriteG(async function* (): AsyncGenerator { const value_ = value + 1; - await testUtils.sleep(100); + await utils.sleep(100); value = value_; return 'last'; }); @@ -339,15 +342,119 @@ describe(RWLockWriter.name, () => { await p4; await p5; await p6; - // Notice that `read2` happens first - // This can chnage if `read2` takes longer to do expect(order).toStrictEqual([ - 'read2', 'read1', + 'read2', 'write1', - 'read4', 'read3', + 'read4', 'write2', ]); }); + test('timeout', async () => { + const lock = new RWLockWriter(); + await withF([lock.read(0)], async ([lock]) => { + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(1); + expect(lock.writerCount).toBe(0); + const f = jest.fn(); + await expect(withF([lock.write(100)], f)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + expect(f).not.toBeCalled(); + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(1); + expect(lock.writerCount).toBe(0); + }); + expect(lock.isLocked()).toBe(false); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(0); + await withF([lock.write(0)], async ([lock]) => { + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(1); + const f = jest.fn(); + await expect(withF([lock.read(100)], f)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + expect(f).not.toBeCalled(); + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(1); + }); + await lock.withReadF(async () => { + const f = jest.fn(); + await expect(lock.withWriteF(f, 100)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + expect(f).not.toBeCalled(); + }, 100); + await lock.withWriteF(async () => { + const f = jest.fn(); + await expect(lock.withReadF(f, 100)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + expect(f).not.toBeCalled(); + }, 100); + await lock.withWriteF(async () => { + const f = jest.fn(); + await expect(lock.withWriteF(f, 100)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + expect(f).not.toBeCalled(); + }, 100); + const gRead = lock.withReadG(async function* () { + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(1); + expect(lock.writerCount).toBe(0); + const f = jest.fn(); + const g = lock.withWriteG(f, 100); + await expect(g.next()).rejects.toThrow(errors.ErrorAsyncLocksTimeout); + expect(f).not.toBeCalled(); + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(1); + expect(lock.writerCount).toBe(0); + }); + await gRead.next(); + const gWrite = lock.withWriteG(async function* () { + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(1); + const f1 = jest.fn(); + const g1 = lock.withReadG(f1, 100); + await expect(g1.next()).rejects.toThrow(errors.ErrorAsyncLocksTimeout); + expect(f1).not.toBeCalled(); + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(1); + const f2 = jest.fn(); + const g2 = lock.withWriteG(f2, 100); + await expect(g2.next()).rejects.toThrow(errors.ErrorAsyncLocksTimeout); + expect(f2).not.toBeCalled(); + expect(lock.isLocked()).toBe(true); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(1); + }); + await gWrite.next(); + expect(lock.isLocked()).toBe(false); + expect(lock.readerCount).toBe(0); + expect(lock.writerCount).toBe(0); + }); + test('timeout waiting for unlock', async () => { + const lock = new RWLockWriter(); + await lock.waitForUnlock(100); + await withF([lock.read()], async ([lock]) => { + await expect(lock.waitForUnlock(100)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + }); + await lock.waitForUnlock(100); + const g = withG([lock.write()], async function* ([lock]) { + await expect(lock.waitForUnlock(100)).rejects.toThrow( + errors.ErrorAsyncLocksTimeout, + ); + }); + await g.next(); + await lock.waitForUnlock(100); + }); }); diff --git a/tests/utils.ts b/tests/utils.ts deleted file mode 100644 index f9d4b34..0000000 --- a/tests/utils.ts +++ /dev/null @@ -1,5 +0,0 @@ -async function sleep(ms: number) { - return await new Promise((r) => setTimeout(r, ms)); -} - -export { sleep };