Skip to main content

usiagent/
player.rs

1//! AIの本体を実装するためのtrait等
2use std::{thread,time};
3use std::time::Instant;
4use std::sync::{atomic, mpsc, Mutex};
5use std::sync::Arc;
6use std::sync::atomic::AtomicBool;
7use std::collections::BTreeMap;
8use std::fmt;
9use std::error::Error;
10use std::convert::TryFrom;
11
12use std::sync::mpsc::{Receiver, Sender};
13
14use command::*;
15use error::*;
16use event::*;
17use shogi::*;
18use protocol::*;
19use rule::*;
20use output::*;
21use Logger;
22use OnErrorHandler;
23use crossbeam_channel::{unbounded, after};
24
25/// プレイヤー(AI本体)の実装
26pub trait USIPlayer<E>: fmt::Debug where E: PlayerError {
27	/// このAIの名前
28	const ID: &'static str;
29	/// このAIの作者
30	const AUTHOR: &'static str;
31	/// サポートしているオブションの一覧をオプション名をキーとしたマップで返す
32	fn get_option_kinds(&mut self) -> Result<BTreeMap<String,SysEventOptionKind>,E>;
33	/// サポートしているオプションに関する設定情報(maxとminの値など)をオプション名をキーとしたマップで返す
34	fn get_options(&mut self) -> Result<BTreeMap<String,UsiOptType>,E>;
35	/// プレイヤーの機能で必要な時間のかかる前処理などをここで行う
36	/// # Arguments
37	/// * `on_keep_alive` - 定期的にGUIに空行を送信してエンジンがフリーズしていないことを通知するためのオブジェクト
38	fn take_ready<W,L>(&mut self, on_keep_alive:OnKeepAlive<W,L>)
39		-> Result<(),E> where W: USIOutputWriter + Send + 'static, L: Logger + Send + 'static;
40	/// オプションを設定する
41	/// # Arguments
42	/// * `name` - オプションの名前
43	/// * `value` - オプションの値
44	fn set_option(&mut self,name:String,value:SysEventOption) -> Result<(),E>;
45	/// ゲーム開始前の処理。対局ごとに毎回呼ばれる
46	fn newgame(&mut self) -> Result<(),E>;
47	/// 局面の初期化。毎回初期局面と現在の局面までの全ての指し手のリストが送られてくる。
48	/// # Arguments
49	/// * `teban` - 初期局面時の手番
50	/// * `ban` - 盤面
51	/// * `ms` - 先手の持ち駒
52	/// * `mg` - 後手の持ち駒
53	/// * `n` - 次の手が何手目か。(USIプロトコルのSFENの原案にあるために存在するが、現在固定で1が送られてくるため無視してかまわない)
54	/// * `m` - 指し手のリスト
55	fn set_position(&mut self,teban:Teban,ban:Banmen,ms:Mochigoma,mg:Mochigoma,n:u32,m:Vec<Move>)
56		-> Result<(),E>;
57	/// 思考開始。この関数の戻り値が指し手となる。AIの実装の核となる部分
58	/// # Arguments
59	/// * `think_start_time` - 思考開始時の時間。通常は現在の時刻だが、go ponderの後に予想した指し手が外れた場合などはstopコマンドを受け取った時刻となる。
60	/// * `limit` - 持ち時間
61	/// * `event_queue` - ユーザーイベントが格納されているキュー。stopコマンドを受信した時やgo ponderの指し手が当たった時,エンジンの終了時などに送られてくる。
62	/// * `info_sender` - infoコマンドを送信するためのオブジェクト。
63	/// * `pinfo_sender` - あらかじめスケジュールされた一定の間隔でinfoコマンドを送信するための機能を持つオブジェクト
64	/// * `on_error_handler` - エラーをログファイルなどに出力するためのオブジェクト
65	fn think<L,S,P>(&mut self,think_start_time:Instant,limit:&UsiGoTimeLimit,event_queue:Arc<Mutex<UserEventQueue>>,
66			info_sender:S,periodically_info:P,on_error_handler:Arc<Mutex<OnErrorHandler<L>>>)
67			-> Result<BestMove,E> where L: Logger + Send + 'static,
68										S: InfoSender,
69										P: PeriodicallyInfo,;
70	/// 思考開始。この関数の戻り値が指し手となる。AIの実装の核となる部分
71	/// # Arguments
72	/// * `limit` - 持ち時間
73	/// * `event_queue` - ユーザーイベントが格納されているキュー。stopコマンドを受信した時やgo ponderの指し手が当たった時,エンジンの終了時などに送られてくる。
74	/// * `info_sender` - infoコマンドを送信するためのオブジェクト。
75	/// * `pinfo_sender` - あらかじめスケジュールされた一定の間隔でinfoコマンドを送信するための機能を持つオブジェクト
76	/// * `on_error_handler` - エラーをログファイルなどに出力するためのオブジェクト
77	fn think_ponder<L,S,P>(&mut self,limit:&UsiGoTimeLimit,event_queue:Arc<Mutex<UserEventQueue>>,
78			info_sender:S,periodically_info:P,on_error_handler:Arc<Mutex<OnErrorHandler<L>>>)
79			-> Result<BestMove,E> where L: Logger + Send + 'static,
80										S: InfoSender + Send + 'static,
81										P: PeriodicallyInfo;
82	/// 詰め将棋回答時に呼ばれる関数
83	/// # Arguments
84	/// * `limit` - 持ち時間
85	/// * `event_queue` - ユーザーイベントが格納されているキュー。stopコマンドを受信した時やgo ponderの指し手が当たった時,エンジンの終了時などに送られてくる。
86	/// * `info_sender` - infoコマンドを送信するためのオブジェクト。
87	/// * `pinfo_sender` - あらかじめスケジュールされた一定の間隔でinfoコマンドを送信するための機能を持つオブジェクト
88	/// * `on_error_handler` - エラーをログファイルなどに出力するためのオブジェクト
89	fn think_mate<L,S,P>(&mut self,limit:&UsiGoMateTimeLimit,event_queue:Arc<Mutex<UserEventQueue>>,
90			info_sender:S,periodically_info:P,on_error_handler:Arc<Mutex<OnErrorHandler<L>>>)
91			-> Result<CheckMate,E> where L: Logger + Send + 'static,
92										 S: InfoSender,
93										 P: PeriodicallyInfo;
94	/// `UserEvent::Stop`イベントがキューに追加されている状態で`dispatch_events`でイベントを処理すると呼ばれる。
95	fn on_stop(&mut self,e:&UserEvent) -> Result<(), E> where E: PlayerError;
96	/// `UserEvent::PonderHit`イベントがキューに追加されている状態で`dispatch_events`でイベントを処理すると呼ばれる。
97	fn on_ponderhit(&mut self,e:&UserEvent) -> Result<(), E> where E: PlayerError;
98	/// 対局終了時に呼ばれる
99	/// # Arguments
100	/// * `s` - 勝敗を表すオブジェクト
101	/// * `event_queue` - ユーザーイベントが格納されているキュー。stopコマンドを受信した時やgo ponderの指し手が当たった時,エンジンの終了時などに送られてくる。
102	/// * `on_error_handler` - エラーをログファイルなどに出力するためのオブジェクト
103	fn gameover<L>(&mut self,s:&GameEndState,
104			event_queue:Arc<Mutex<UserEventQueue>>,
105			on_error_handler:Arc<Mutex<OnErrorHandler<L>>>) -> Result<(),E> where L: Logger, Arc<Mutex<OnErrorHandler<L>>>: Send + 'static;
106	/// `UserEvent::Quit`イベントがキューに追加されている状態で`dispatch_events`でイベントを処理すると呼ばれる。
107	fn on_quit(&mut self,e:&UserEvent) -> Result<(), E> where E: PlayerError;
108	/// 終了時に呼ばれる関数
109	fn quit(&mut self) -> Result<(),E>;
110	/// イベントを処理する関数。これにイベントキューを渡すか`EventDispatcher`を実装したオブジェクトの`dispatch_events`にイベントキューを渡すまでイベントは処理されない。
111	/// # Arguments
112	/// * `event_queue` - ユーザーイベントが格納されているキュー。stopコマンドを受信した時やgo ponderの指し手が当たった時,エンジンの終了時などに送られてくる。
113	/// * `on_error_handler` - エラーをログファイルなどに出力するためのオブジェクト
114	fn handle_events<'a,L>(&mut self,event_queue:&'a Mutex<UserEventQueue>,
115						on_error_handler:&Mutex<OnErrorHandler<L>>) -> Result<bool,E>
116						where L: Logger, E: Error + fmt::Debug,
117								Arc<Mutex<OnErrorHandler<L>>>: Send + 'static,
118								EventHandlerError<UserEventKind,E>: From<E> {
119		Ok(match self.dispatch_events(event_queue,&on_error_handler) {
120			Ok(_)=> true,
121			Err(ref e) => {
122				let _ = on_error_handler.lock().map(|h| h.call(e));
123				false
124			}
125		})
126	}
127
128	/// `USIPlayer::handle_events`から呼ばれる内部関数。イベントキュー内のイベントを処理する。
129	/// # Arguments
130	/// * `event_queue` - ユーザーイベントが格納されているキュー。stopコマンドを受信した時やgo ponderの指し手が当たった時,エンジンの終了時などに送られてくる。
131	/// * `on_error_handler` - エラーをログファイルなどに出力するためのオブジェクト
132	fn dispatch_events<'a,L>(&mut self, event_queue:&'a Mutex<UserEventQueue>,
133						on_error_handler:&Mutex<OnErrorHandler<L>>) ->
134						Result<(), EventDispatchError<'a,UserEventQueue,UserEvent,E>>
135							where L: Logger, E: Error + fmt::Debug,
136									Arc<Mutex<OnErrorHandler<L>>>: Send + 'static,
137									EventHandlerError<UserEventKind,E>: From<E> {
138		let events = {
139			event_queue.lock()?.drain_events()
140		};
141
142		let mut has_error = false;
143
144		for e in &events {
145			match e {
146				&UserEvent::Stop => {
147					match self.on_stop(e) {
148						Ok(_) => (),
149						Err(ref e) => {
150							let _ = on_error_handler.lock().map(|h| h.call(e));
151							has_error = true;
152						}
153					};
154				},
155				&UserEvent::PonderHit(_) => {
156					match self.on_ponderhit(e) {
157						Ok(_) => (),
158						Err(ref e) => {
159							let _ = on_error_handler.lock().map(|h| h.call(e));
160							has_error = true;
161						}
162					};
163				},
164				&UserEvent::Quit => {
165					match self.on_quit(e) {
166						Ok(_) => (),
167						Err(ref e) => {
168							let _ = on_error_handler.lock().map(|h| h.call(e));
169							has_error = true;
170						}
171					};
172				}
173			};
174		}
175
176		match has_error {
177			true => Err(EventDispatchError::ContainError),
178			false => Ok(()),
179		}
180	}
181
182	/// 手のリストを現在の局面に適用した結果を返す
183	/// # Arguments
184	/// * `state` - 手の列挙に使うビットボードと盤面などの内部状態を持つオブジェクト
185	/// * `teban` - 局面開始時の手番
186	/// * `mc` - 局面開始時の持ち駒
187	/// * `m` - 開始局面から現在までの指し手のリスト
188	/// * `r` - コールバック関数に渡され関数の戻り値の一部となるオブジェクト(任意の型)
189	/// * `f` - 手の適用のたびに呼ばれるコールバック関数
190	fn apply_moves<T,F>(&self,mut state:State,
191						mut teban:Teban,
192						mut mc:MochigomaCollections,
193						m:&Vec<AppliedMove>,mut r:T,mut f:F)
194		-> (Teban,State,MochigomaCollections,T)
195		where F: FnMut(&Self,Teban,&Banmen,
196						&MochigomaCollections,&Option<AppliedMove>,
197						&Option<MochigomaKind>,T) -> T {
198
199		for m in m {
200			match Rule::apply_move_none_check(&state,teban,&mc,*m) {
201				(next,nmc,o) => {
202					r = f(self,teban,&state.get_banmen(),&mc,&Some(*m),&o,r);
203					state = next;
204					mc = nmc;
205					teban = teban.opposite();
206				}
207			}
208		}
209		r = f(self,teban,&state.get_banmen(),&mc,&None,&None,r);
210
211		(teban,state,mc,r)
212	}
213}
214/// infoコマンドの発行スレッドに対してコマンドの出力、スレッドの停止などを通知するためのメッセージオブジェクト
215#[derive(Clone, Debug)]
216pub enum UsiInfoMessage {
217	/// infoコマンドのサブコマンドのリスト
218	Commands(Vec<UsiInfoSubCommand>),
219	/// 送信バッファの中身を全て書き込む
220	Flush,
221	/// infoコマンド発行スレッドを停止させる
222	Quit,
223}
224/// infoコマンドを出力する
225pub trait InfoSender: Clone + Send + 'static {
226	/// infoコマンドを出力する
227	///
228	/// # Arguments
229	/// * `commands` - infoサブコマンドのリスト
230	fn send(&mut self,commands:Vec<UsiInfoSubCommand>) -> Result<(), InfoSendError>;
231	/// infoコマンドを遅延なしで出力する
232	///
233	/// # Arguments
234	/// * `commands` - infoサブコマンドのリスト
235	fn send_immediate(&mut self,commands:Vec<UsiInfoSubCommand>) -> Result<(), InfoSendError>;
236	fn flush(&mut self) -> Result<(), InfoSendError> {
237		Ok(())
238	}
239}
240/// infoコマンドを標準出力へ出力する`InfoSender`の実装
241pub struct USIInfoSender<W> where W: USIOutputWriter + Send + 'static {
242	worker:InfoSendWorker<W>
243}
244impl<W> USIInfoSender<W> where W: USIOutputWriter + Send + 'static {
245	/// `USIInfoSender`の生成
246	///
247	/// # Arguments
248	/// * `worker` - infoコマンド出力スレッドへ通知するためのWorker
249	pub fn new(worker:InfoSendWorker<W>) -> USIInfoSender<W> {
250		USIInfoSender {
251			worker:worker
252		}
253	}
254}
255impl<W> InfoSender for USIInfoSender<W> where W: USIOutputWriter + Send + 'static {
256	fn send(&mut self,commands:Vec<UsiInfoSubCommand>) -> Result<(), InfoSendError> {
257		if let Err(_) = self.worker.sender.send(UsiInfoMessage::Commands(commands)) {
258			Err(InfoSendError::Fail(String::from(
259				"info command send failed.")))
260		} else {
261			Ok(())
262		}
263	}
264	
265	fn send_immediate(&mut self, commands: Vec<UsiInfoSubCommand>) -> Result<(), InfoSendError> {
266		self.send(commands)?;
267		Ok(self.flush()?)
268	}
269
270	fn flush(&mut self) -> Result<(), InfoSendError> {
271		if let Err(_) = self.worker.sender.send(UsiInfoMessage::Flush) {
272			Err(InfoSendError::Fail(String::from(
273				"info sender buffer flush failed.")))
274		} else {
275			Ok(())
276		}
277	}
278}
279impl<W> Clone for USIInfoSender<W> where W: USIOutputWriter + Send + 'static {
280	fn clone(&self) -> USIInfoSender<W> {
281		USIInfoSender::new(self.worker.clone())
282	}
283}
284/// USIInfoSenderでinfoコマンドを短い間隔で投げすぎないようウエイトを書けながら順次送信するためのオブジェクト
285pub struct InfoSendWorker<W> where W: USIOutputWriter {
286	sender:Sender<UsiInfoMessage>,
287	writer:Arc<Mutex<W>>,
288	quited:Arc<AtomicBool>
289}
290const INFO_SEND_BUFFER_SIZE:usize = 100;
291
292impl<W> InfoSendWorker<W> where W: USIOutputWriter {
293	/// `InfoSendWorker`の生成
294	///
295	/// # Arguments
296	/// * `writer` - 出力へ書き込みためのwriter
297	/// * `notifier` - 処理の完了通知用のSender
298	/// * `on_error_handler` - エラーをログファイルなどに出力するためのオブジェクト
299	pub fn new<L>(writer:Arc<Mutex<W>>,
300			   notifier:Sender<()>,
301			   on_error_handler:Arc<Mutex<OnErrorHandler<L>>>)
302		-> InfoSendWorker<W> where L: Logger,
303								   Arc<Mutex<W>>: Send + 'static,
304								   Arc<Mutex<OnErrorHandler<L>>>: Send + 'static {
305		let mut buffer = Vec::with_capacity(INFO_SEND_BUFFER_SIZE);
306
307		let (sender,receiver) = mpsc::channel();
308		{
309			let writer = writer.clone();
310
311			thread::spawn(move || {
312				loop {
313					match receiver.recv() {
314						Ok(UsiInfoMessage::Commands(commands)) => {
315							let command = match UsiInfoCommand(commands).to_usi_command() {
316								Ok(command) => command,
317								Err(ref e) => {
318									let _ = on_error_handler.lock().map(|h| h.call(e));
319									break;
320								}
321							};
322
323							buffer.push(command);
324
325							if buffer.len() >= INFO_SEND_BUFFER_SIZE {
326								match writer.lock() {
327									Err(ref e) => {
328										let _ = on_error_handler.lock().map(|h| h.call(e));
329										break;
330									},
331									Ok(ref writer) => {
332										if let Err(ref e) = writer.write(&buffer) {
333											let _ = on_error_handler.lock().map(|h| h.call(e));
334											break;
335										}
336										buffer.clear();
337									}
338								}
339							}
340						},
341						Ok(UsiInfoMessage::Flush) => {
342							if buffer.len() > 0 {
343								match writer.lock() {
344									Err(ref e) => {
345										let _ = on_error_handler.lock().map(|h| h.call(e));
346									},
347									Ok(ref writer) => {
348										if let Err(ref e) = writer.write(&buffer) {
349											let _ = on_error_handler.lock().map(|h| h.call(e));
350										}
351									}
352								}
353							}
354						},
355						Ok(UsiInfoMessage::Quit) => {
356							if buffer.len() > 0 {
357								match writer.lock() {
358									Err(ref e) => {
359										let _ = on_error_handler.lock().map(|h| h.call(e));
360									},
361									Ok(ref writer) => {
362										if let Err(ref e) = writer.write(&buffer) {
363											let _ = on_error_handler.lock().map(|h| h.call(e));
364										}
365									}
366								}
367							}
368
369							break;
370						},
371						Err(ref e) => {
372							let _ = on_error_handler.lock().map(|h| h.call(e));
373							break;
374						}
375					}
376				}
377
378				if let Err(ref e) = notifier.send(()) {
379					let _ = on_error_handler.lock().map(|h| h.call(e));
380				}
381			});
382		}
383
384		InfoSendWorker {
385			sender:sender,
386			writer:writer,
387			quited:Arc::new(AtomicBool::new(false))
388		}
389	}
390
391	/// infoコマンド送信スレッドを終了させる
392	pub fn quit(&self,receiver:Receiver<()>) -> Result<(), InfoSendWorkerError> {
393		if !self.quited.swap(true,atomic::Ordering::Release) {
394			self.sender.send(UsiInfoMessage::Quit)?;
395			receiver.recv()?;
396		}
397		Ok(())
398	}
399}
400impl<W> Clone for InfoSendWorker<W> where W: USIOutputWriter {
401	fn clone(&self) -> Self {
402		InfoSendWorker {
403			sender:self.sender.clone(),
404			writer:self.writer.clone(),
405			quited:self.quited.clone()
406		}
407	}
408}
409/// コンソールへ出力する`InfoSender`の実装(出力用に別にスレッドを持ってはおらず呼び出し時に直接出力する)
410pub struct ConsoleInfoSender {
411	writer:USIStdOutputWriter,
412	silent:bool,
413}
414impl ConsoleInfoSender {
415	/// `ConsoleInfoSender`の生成
416	///
417	/// # Arguments
418	/// * `silent` - infoコマンドを出力するか否かのフラグ。`true`の場合、出力しない
419	pub fn new(silent:bool) -> ConsoleInfoSender {
420		ConsoleInfoSender {
421			writer:USIStdOutputWriter::new(),
422			silent:silent
423		}
424	}
425}
426impl InfoSender for ConsoleInfoSender {
427	fn send(&mut self,commands:Vec<UsiInfoSubCommand>) -> Result<(), InfoSendError> {
428		if !self.silent {
429			let lines = vec![commands.to_usi_command()?];
430
431			if let Err(_) =  self.writer.write(&lines) {
432				return Err(InfoSendError::Fail(String::from(
433					"info command send failed.")))
434			}
435		}
436		Ok(())
437	}
438
439	fn send_immediate(&mut self, commands: Vec<UsiInfoSubCommand>) -> Result<(), InfoSendError> {
440		self.send(commands)
441	}
442}
443impl Clone for ConsoleInfoSender {
444	fn clone(&self) -> ConsoleInfoSender {
445		ConsoleInfoSender::new(self.silent)
446	}
447}
448/// 初期化処理時にKeepAliveとして空行を送信する
449pub trait KeepAliveSender {
450	/// 空行を送信する
451	fn send(&self);
452	#[must_use]
453	/// Dropされる前の間指定された間隔(単位は秒)で空行を送信するオブジェクトを生成する
454	///
455	/// # Arguments
456	/// * `sec` - 空行を送信する間隔(単位は秒単位)
457	///
458	/// note: このメソッドから返された値を_から始まる任意の名前の変数に格納して、
459	///     KeepAliveの送信が必要なくなるタイミングまで保持してください。
460	///       このオブジェクトがスコープを抜けてdropされた時点でKeepAlive送信スレッドには停止要求が投げられ、
461	///       その後KeepAlive送信処理は終了します。
462	fn auto(&self,sec:u64) -> AutoKeepAlive;
463}
464/// `KeepAliveSender`の実装
465pub struct OnKeepAlive<W,L> where W: USIOutputWriter + Send + 'static, L: Logger + Send + 'static {
466	/// * `writer` - USIコマンドを出力するためのオブジェクト。実装によって標準出力以外へ書き込むものを指定することも可能。
467	writer:Arc<Mutex<W>>,
468	/// * `on_error_handler` - エラーをログファイルなどに出力するためのオブジェクト
469	on_error_handler:Arc<Mutex<OnErrorHandler<L>>>
470}
471impl<W,L> OnKeepAlive<W,L> where W: USIOutputWriter + Send + 'static, L: Logger + Send + 'static {
472	/// `OnKeepAlive`の生成
473	///
474	/// # Arguments
475	/// * `writer` - USIコマンドを出力するためのオブジェクト。実装によって標準出力以外へ書き込むものを指定することも可能。
476	/// * `on_error_handler` - エラーをログファイルなどに出力するためのオブジェクト
477	pub fn new(writer:Arc<Mutex<W>>,on_error_handler:Arc<Mutex<OnErrorHandler<L>>>) -> OnKeepAlive<W,L> {
478		OnKeepAlive {
479			writer:writer,
480			on_error_handler:on_error_handler
481		}
482	}
483}
484impl<W,L> KeepAliveSender for OnKeepAlive<W,L> where W: USIOutputWriter + Send + 'static, L: Logger + Send + 'static {
485	fn send(&self) {
486		match self.writer.lock() {
487			Err(ref e) => {
488				let _ = self.on_error_handler.lock().map(|h| h.call(e));
489			},
490			Ok(ref writer) => {
491				if let Err(ref e) = writer.write(&vec![String::from("")]) {
492					let _ = self.on_error_handler.lock().map(|h| h.call(e));
493				}
494			}
495		};
496	}
497
498	#[must_use]
499	fn auto(&self,sec:u64) -> AutoKeepAlive {
500		AutoKeepAlive::new(sec,self.clone())
501	}
502}
503impl<W,L> Clone for OnKeepAlive<W,L> where W: USIOutputWriter + Send + 'static, L: Logger + Send + 'static {
504	fn clone(&self) -> OnKeepAlive<W,L> {
505		OnKeepAlive {
506			writer:self.writer.clone(),
507			on_error_handler:self.on_error_handler.clone()
508		}
509	}
510}
511/// KeepAliveの送信を指定された間隔で定期的に行う
512///
513/// note: このオブジェクトは`KeepAliveSender`を実装した型の`auto`メソッドから返されますが、
514///       必ず返された値を_から始まる任意の名前の変数に格納して、KeepAliveの送信が必要なくなるタイミングまで保持してください。
515///       このオブジェクトがスコープを抜けてdropされた時点でKeepAlive送信スレッドには停止要求が投げられ、
516///       その後KeepAlive送信処理は終了します。
517pub struct AutoKeepAlive {
518	/// Drop時に送信スレッドに停止メッセージを送るためのSender
519	stop_sender:crossbeam_channel::Sender<()>
520}
521impl AutoKeepAlive {
522	/// `AutoKeepAlive`の生成
523	///
524	/// # Arguments
525	/// * `sec` - KeepAlive送信の間隔(単位は秒単位)
526	/// * `on_keep_alive` - KeepAlive送信用オブジェクト
527	fn new<W,L>(sec:u64,on_keep_alive: OnKeepAlive<W,L>)
528		-> AutoKeepAlive where W: USIOutputWriter + Send + 'static, L: Logger + Send + 'static {
529		let(s,r) = unbounded();
530
531		std::thread::spawn(move || {
532			let mut timeout = after(time::Duration::from_secs(sec));
533
534			loop {
535				select! {
536					recv(r) -> _ => {
537						return;
538					},
539					recv(timeout) -> _ => {
540						on_keep_alive.send();
541						timeout = after(time::Duration::from_secs(sec));
542					}
543				}
544			}
545		});
546
547		AutoKeepAlive {
548			stop_sender:s
549		}
550	}
551}
552impl Drop for AutoKeepAlive {
553	fn drop(&mut self) {
554		let _ = self.stop_sender.send(());
555	}
556}
557/// 一定時間ごとに定期的に送信するinfoコマンドの送信用
558/// これ自体はコマンドの送信を行わない。dropされたタイミングで送信用スレッドを止める役割を担う
559///
560/// note: このオブジェクトは`PeriodicallyInfo`を実装した型の`start`メソッドから返されますが、
561///       必ず返された値を_から始まる任意の名前の変数に格納して、
562///       定期的伊送信するinfoコマンドの送信が必要なくなるタイミングまで保持してください。
563///       このオブジェクトがスコープを抜けてdropされた時点で定期的に送信するinfoコマンド送信スレッドには停止要求が投げられ、
564///       その後送信処理は終了します。
565pub struct PeriodicallyInfoSender {
566	/// * `stop_sender` Drop時に送信スレッドに停止メッセージを送るためのSender
567	stop_sender:crossbeam_channel::Sender<()>,
568}
569impl PeriodicallyInfoSender {
570	/// * `stop_sender` Drop時に送信スレッドに停止メッセージを送るためのSender
571	pub fn new(stop_sender:crossbeam_channel::Sender<()>) -> PeriodicallyInfoSender {
572		PeriodicallyInfoSender {
573			stop_sender:stop_sender
574		}
575	}
576}
577impl Drop for PeriodicallyInfoSender {
578	fn drop(&mut self) {
579		let _ = self.stop_sender.send(());
580	}
581}
582/// 一定時間ごとに定期的に送信するinfoコマンドの送信用
583pub trait PeriodicallyInfo: Send + 'static {
584	#[must_use]
585	/// 送信するコマンドの生成用コールバックの登録と共に送信開始
586	///
587	/// # Arguments
588	/// * `interval` - infoコマンド送信の間隔(単位はミリ秒))
589	/// * `info_generator` - `UsiInfoSubCommand`のリストを返すジェネレータ。定期的に呼びdされ返されたコマンドを僧院する。
590	/// * `on_error_handler` - エラーをログファイルなどに出力するためのオブジェクト
591	///
592	/// note: このメソッドから返された値を_から始まる任意の名前の変数に格納して、
593	///       定期的伊送信するinfoコマンドの送信が必要なくなるタイミングまで保持してください。
594	///       このオブジェクトがスコープを抜けてdropされた時点で定期的に送信するinfoコマンド送信スレッドには停止要求が投げられ、
595	///       その後送信処理は終了します。
596	fn start<F,L>(self,interval:u64,info_generator:F,on_error_handler:&Arc<Mutex<OnErrorHandler<L>>>)
597		-> PeriodicallyInfoSender where F: FnMut() -> Vec<UsiInfoSubCommand> + Sized + Send + 'static,
598			  L: Logger + Send + 'static;
599}
600pub struct USIPeriodicallyInfo<W> where W: USIOutputWriter + Send + 'static {
601	/// * `writer` - USIコマンドを出力するためのオブジェクト。実装によって標準出力以外へ書き込むものを指定することも可能。
602	writer:Arc<Mutex<W>>,
603	/// * `silent` - infoコマンドを出力するか否かのフラグ。`true`の場合、出力しない
604	silent:bool
605}
606impl<W> USIPeriodicallyInfo<W>
607	where W: USIOutputWriter + Send + 'static {
608	/// `USIPeriodicallyInfoSender`の生成
609	///
610	/// # Arguments
611	/// * `writer` - USIコマンドを出力するためのオブジェクト。実装によって標準出力以外へ書き込むものを指定することも可能。
612	/// * `silent` - infoコマンドを出力するか否かのフラグ。`true`の場合、出力しない
613	pub fn new(writer:Arc<Mutex<W>>,silent:bool) -> USIPeriodicallyInfo<W> {
614		USIPeriodicallyInfo {
615			writer:writer,
616			silent:silent
617		}
618	}
619}
620impl<W> PeriodicallyInfo for USIPeriodicallyInfo<W>
621	where W: USIOutputWriter + Send + 'static {
622
623	#[must_use]
624	fn start<F,L>(self,interval:u64,info_generator:F,on_error_handler:&Arc<Mutex<OnErrorHandler<L>>>)
625		-> PeriodicallyInfoSender where F: FnMut() -> Vec<UsiInfoSubCommand> + Send + 'static,
626			  L: Logger + Send + 'static {
627		let (s,r) = unbounded();
628
629		let writer = self.writer.clone();
630		let mut info_generator = info_generator;
631		let silent = self.silent;
632		let on_error_handler = on_error_handler.clone();
633
634		std::thread::spawn(move || {
635			let mut timeout = after(time::Duration::from_millis(interval));
636
637			loop {
638				select! {
639					recv(r) -> _ => {
640						return;
641					},
642					recv(timeout) -> _ => {
643						match UsiOutput::try_from(&UsiCommand::UsiInfo(info_generator())) {
644							Ok(UsiOutput::Command(ref s)) => {
645								match writer.lock() {
646									Err(ref e) => {
647										let _ = on_error_handler.lock().map(|h| h.call(e));
648										break;
649									},
650									Ok(ref writer) => {
651										if !silent {
652											let _ = writer.write(s).map_err(|e| on_error_handler.lock().map(|h| h.call(&e)));
653										}
654									}
655								};
656							},
657							Err(ref e) => {
658								let _ = on_error_handler.lock().map(|h| h.call(e));
659								break;
660							}
661						}
662						timeout = after(time::Duration::from_millis(interval));
663					}
664				}
665			}
666		});
667
668		PeriodicallyInfoSender::new(s)
669	}
670}
671impl<W> Clone for USIPeriodicallyInfo<W> where W: USIOutputWriter + Send + 'static {
672	fn clone(&self) -> USIPeriodicallyInfo<W> {
673		USIPeriodicallyInfo {
674			writer:self.writer.clone(),
675			silent:self.silent
676		}
677	}
678}
679pub struct ConsolePeriodicallyInfo {
680	inner:USIPeriodicallyInfo<USIStdOutputWriter>
681}
682impl ConsolePeriodicallyInfo {
683	/// `ConsolePeriodicallyInfoSender`の生成
684	///
685	/// # Arguments
686	/// * `silent` - infoコマンドを出力するか否かのフラグ。`true`の場合、出力しない
687	pub fn new(silent:bool) -> ConsolePeriodicallyInfo {
688		ConsolePeriodicallyInfo {
689			inner:USIPeriodicallyInfo::new(
690				Arc::new(Mutex::new(USIStdOutputWriter::new())),
691					  silent
692			)
693		}
694	}
695}
696impl PeriodicallyInfo for ConsolePeriodicallyInfo {
697	#[must_use]
698	fn start<F,L>(self,interval:u64,info_generator:F,on_error_handler:&Arc<Mutex<OnErrorHandler<L>>>)
699		-> PeriodicallyInfoSender where F: FnMut() -> Vec<UsiInfoSubCommand> + Send + 'static,
700											  L: Logger + Send + 'static {
701		self.inner.start(interval,info_generator,on_error_handler)
702	}
703}
704impl Clone for ConsolePeriodicallyInfo {
705	fn clone(&self) -> ConsolePeriodicallyInfo {
706		ConsolePeriodicallyInfo {
707			inner:self.inner.clone()
708		}
709	}
710}