@koba789 Deref 実装してませんでした……
いや、これ普通に std と conflict するとか言われてるし blanket impl あるじゃん
よく見たら
impl<T, E> PartialEq<Result<T, E> for Result<T, E>
where T: PartialEq<T>, E: PartialEq<E>
はあるけど、
impl<T, E, U, F> PartialEq<Result<U, F>> for Result<T, E>
where T: PartailEq<U>, E: PartialEq<F>
がないやんけ!!!
https://doc.rust-lang.org/1.71.1/std/result/enum.Result.html#method.as_ref
で、 Result::as_ref() は Result<&T, &E> しか返してくれないので AsRef<U> for T が使えなくて、 Deref<Target=U> for T も意図的に実装を避けているので Result::as_deref() も使えない
このアカウントは、notestockで公開設定になっていません。
仕方ないので
fn ok_as_ref<T, U: ?Sized, E>(res: &Result<T, E>) -> Result<&U, &E>
where
T: AsRef<U>,
{
match res {
Ok(v) => Ok(v.as_ref()),
Err(e) => Err(e),
}
}
みたいなのを用意して、
assert_eq!(ok_as_ref(&foo()), Ok("hello"));
のようにして解決した。あまり愉快ではないが……
assert_eq!(foo().map(AsRef::<str>::as_ref), Ok("hello"));
みたいなのは map でさっさと T が死んでしまって参照が無効になるので駄目
Nmtoken, Name, QName, NCName, URIQualifiedName, EQName, およびこれらにキャッシュ情報を付けた版
よくよく考えたら、パーサを定義すると同時に「そのパーサが受理するような文字列だけを値として持つような文字列型」も一緒に定義されてくれないと不便極まりないんだよな。自動化するしかない
型を作ってからパーサを書くというのがそもそも順序として微妙。パーサを書いたらそのうちいくつかについて型を割り当てたくなるというのが正しい。だったら根本的にはパーサに何かマーク付けただけで型が生えてきてくれないと困る。
でもなぁ……カスタムのスライス型に適宜トレイトを付けたり付けなかったりを制御しつつ macro で関連実装のボイラープレートを削減するという試み、何回かやって使えるには使えるものができているけど毎回敗北している
compiler magic っぽく振る舞ってほしくて、 proc macro が呼び出された context の情報が欲しい。
impl AsRef<str> for Foo {
custom_slicer::auto_impl!();
}
みたいに書いたら
fn as_ref(&self) -> AsRef<str> {
<Foo as custom_slicer::CustomSlice>::as_inner(self)
}
みたいに先祖ブロックのコンテキストを参照してコード生成してくれるようなものがほしいのよ
ここで引数に与える方法で
custom_slicer::auto_impl!(impl AsRef<str> for Foo);
みたいにするのももちろん手ではあるんだが、ちょっと文法的にあまり素敵でないというか……
`OwnedSliceSpec::inner_as_slice_inner` design is always broken for incompatible inner types · Issue #1 · lo48576/validated-slice
https://github.com/lo48576/validated-slice/issues/1
思い出して鬱になってきた
proc macro で再挑戦してみるかねぇ。その価値はあると今でも思うんだけど、いかんせん実装がつらい
custom-slice-macros - crates.io: Rust Package Registry
https://crates.io/crates/custom-slice-macros
トレイト実装を #[derive(..)] 形式にしようとするとつらいので、次やるならこうはしない
validated-slice/tests/ascii_str.rs at v0.2.0 · lo48576/validated-slice
https://github.com/lo48576/validated-slice/blob/v0.2.0/tests/ascii_str.rs
ゥヮ
現時点での知見としては、
* トレイト実装の自動化は、 #[derive(..)] ではなく impl<..> Trait<..> for Ty<..> {} のような実際の文法に近い形で指定しないとかなりつらい
* underlying slice type と conversion source は完全に分離しないとつらい
などがある #らりおメモ
underlying と source の分離というのは、たとえば struct DatetimeStr(str); と struct DatetimeStr([u8]); のどちらも可能だし状況次第でどちらにも優位性があるのでどうするか、というのが underlying type の選択。
DatetimeStr::try_from(&str) と DatetimeStr::try_from(&[u8]) の両方が可能だけどどう実装しようか、というのが conversion source の問題。
impl TryFrom<&[u8]> for DatetimeStr {
type Error = ..;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
core::str::from_utf8(bytes)
.map_err(Self::Error::from)
.and_then(Self::try_from)
}
}
みたいにして conversion source をまとめることもできるんだが、これだと parsing で重複したコストがかかることになって非効率な場合があるので、実はよろしくない
たとえば「バイト列に対して実装されたパーサで validation を行っているが文字列の内部では str を持ちたい」みたいな場合に str としての validation は完全に無駄になる
で、そもそもそのような場合だと &[u8] に対して validation したことをもって &str としても valid であるという知識をユーザが暗黙に与えることになるので、たとえばパーサのバグどころかマクロの使い方のミス程度のことでたやすく UB になりかねない。仕方ないといえば仕方ないかもしれないが、さすがにそれはライブラリとして微妙すぎる
尤もマクロの使い方の話をするなら、そもそも #[repr(transparent)] を型定義で忘れていても derive macros でない限り型定義のトークン列を得られないのでどうしようもないなどの問題もあり、一番最初の段階から既にどうしようもなさがあるが
だんだん思い出してきた、 owned types と borrowed slice types の相互作用とか実装の移譲も考えないといけないのだった……
このアカウントは、notestockで公開設定になっていません。
おねショタが潜んでいるのを見出してしまって何かの隠語表現なのかと頭を捻っていたが、もしかして文字通りの意味か……
なんかインスタグラムにありそうとか言われそうなとんでもなくハッシュタグだらけの写真投稿流れてきて、いやそういえば fediverse なんだから PixelFed みたいなサーバから流れてきててもおかしくないよなと思って元サイト見てみたら Mastodon だった
このアカウントは、notestockで公開設定になっていません。
クイズ:
LC_TIME=ja_JP.utf-8 環境でカレンダーを表示してくれるのは、以下のどれ?
クイズ2:
前述のクイズの答えの後ろに「2000」を付けて実行した場合の結果は?
ロケールクイズの答えですが、
* 「cal 8月」で8月のカレンダーが表示される。
* 「㋇」「8月」「八月」「葉月」は月として認識されない
* 「cal 8 2000」のようにすると2000年8月が表示されるのに「cal 8月 2000」にするとエラーになる
でした!