summary refs log tree commit diff stats
path: root/tests/iter/tscheduler.nim
blob: f4b04f311ff845625737ba920a428f2fd6ff63b8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
discard """
  output: '''a1 5
a2 10
a1 3
a1 1
a2 8
a2 6
a2 4
a2 2'''
  disabled: "true"
"""

import os, strutils, times, algorithm


type TaskFn = iterator (): float

type Task = object
    coro: TaskFn
    next_run: float


type Scheduler = object
    tasks: seq[Task]


proc newScheduler(): Scheduler =
    var s = Scheduler()
    s.tasks = @[]
    return s


proc start(this: var Scheduler, task: TaskFn) =
    var t = Task()
    t.coro = task
    t.next_run = 0.0
    this.tasks.add(t)


proc run(this: var Scheduler) =
    while this.tasks.len > 0:
        var dead: seq[int] = @[]
        for i in this.tasks.low..this.tasks.high:
            var task = this.tasks[i]
            if finished(task.coro):
                dead.add(i)
                continue
            if task.next_run <= epochTime():
                task.next_run = task.coro() + epochTime()
            this.tasks[i] = task
        for i in dead:
            this.tasks.delete(i)
        if this.tasks.len > 0:
            sort(this.tasks, proc (t1: Task, t2: Task): int = cmp(t1.next_run, t2.next_run))
            sleep(int((this.tasks[0].next_run - epochTime()) * 1000))


iterator a1(): float {.closure.} =
    var k = 5
    while k > 0:
        echo "a1 $1" % [$k]
        dec k, 2
        yield 0.5


iterator a2(): float {.closure.} =
    var k = 10
    while k > 0:
        echo "a2 $1" % [$k]
        dec k, 2
        yield 1.5


var sched = newScheduler()
sched.start(a1)
sched.start(a2)
sched.run()
{ color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
# Copyright (c) 2009, 2010 hut <hut@lavabit.com>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

import os
from curses import *
from curses.ascii import *
from inspect import getargspec, ismethod

from ranger import RANGERDIR
from ranger.gui.widgets import console_mode as cmode
from ranger.container.bookmarks import ALLOWED_KEYS as ALLOWED_BOOKMARK_KEYS

def make_abbreviations(command_list):
	def bind(*args):
		lastarg = args[-1]
		if hasattr(lastarg, '__call__'):
			# do the binding
			command_list.bind(lastarg, *args[:-1])
		else:
			# act as a decorator. eg:
			#    @bind('a')
			#    def do_stuff(arg):
			#       arg.fm.ui.do_stuff()
			#
			# is equivalent to:
			#    bind('a', lambda arg: arg.fm.ui.do_stuff())
			return lambda fnc: command_list.bind(fnc, *args)
	
	def hint(*args):
		command_list.hint(args[-1], *args[:-1])

	def alias(*args):
		command_list.alias(*args)

	return bind, hint, alias

class Wrapper(object):
	def __init__(self, firstattr):
		self.__firstattr__ = firstattr

	def __getattr__(self, attr):
		def wrapper(*real_args, **real_keywords):
			def function(command_argument):
				args, kws = real_args, real_keywords
				number = command_argument.n
				obj = getattr(command_argument, self.__firstattr__)
				fnc = getattr(obj, attr)
				if number is not None:
					args, kws = replace_narg(number, fnc, args, kws)
				return fnc(*args, **kws)
			return function
		return wrapper

# fm.enter_dir('~') is translated into lambda arg: arg.fm.enter_dir('~')
# this makes things like this possible:
# bind('gh', fm.enter_dir('~'))
#
# but NOT: (note the 2 dots)
# bind('H', fm.history.go(-1))
#
# for something like that, use the long version:
# bind('H', lambda arg: arg.fm.history.go(-1))
#
# If the method has an argument named "narg", pressing a number before
# the key will pass that number as the narg argument. If you want the
# same behaviour in a custom lambda function, you can write:
# bind('gg', fm.move_pointer(absolute=0))
# as:
# bind('gg', lambda arg: narg(arg.n, arg.fm.move_pointer, absolute=0))

fm = Wrapper('fm')
wdg = Wrapper('wdg')


NARG_KEYWORD = 'narg'

def narg(number_, function_, *args_, **keywords_):
	"""
	This applies the replace_narg function to the arguments and keywords
	and directly runs this function.

	Example:
	def foo(xyz, narg): return hash((xyz, narg))

	narg(50, foo, 123) == foo(123, narg=50)
	"""
	args, keywords = replace_narg(number_, function_, args_, keywords_)
	print(args, keywords)
	return function_(*args, **keywords)

def replace_narg(number, function, args, keywords):
	"""
	This function returns (args, keywords) with one little change:
	if <function> has a named argument called "narg", args and keywords
	will be modified so that the value of "narg" will be <number>.

	def foo(xyz, narg): pass

	replace_narg(666, foo, (), {'narg': 10, 'xyz': 5})
	=> (), {'narg': 666, 'xyz': 5}

	replace_narg(666, foo, (1, 2), {})
	=> (1, 666), {}
	"""
	argspec = getargspec(function).args
	if NARG_KEYWORD in argspec:
		try:
			# is narg in args?
			args = list(args)
			index = argspec.index(NARG_KEYWORD)
			if ismethod(function):
				index -= 1  # because of 'self'
			args[index] = number
		except (ValueError, IndexError):
			# is narg in keywords?
			keywords = dict(keywords)
			keywords[NARG_KEYWORD] = number
	return args, keywords