mycelium_trace/
writer.rs

1//! Abstractions for creating [`fmt::Write`] instances.
2//!
3//! [`fmt::Write`]: mycelium_util::fmt::Write
4use crate::color::{Color, SetColor};
5use maitake::sync::{
6    blocking::{Mutex, MutexGuard, RawMutex},
7    spin::Spinlock,
8};
9use mycelium_util::fmt::{self, Debug};
10use tracing_core::Metadata;
11
12/// A type that can create [`fmt::Write`] instances.
13///
14/// This trait is already implemented for function pointers and
15/// immutably-borrowing closures that return an instance of [`fmt::Write`],
16/// Additionally, it is implemented for [`maitake::sync::blocking::Mutex`]
17/// when the type inside the mutex implements [`fmt::Write`] and the `Lock` type
18/// implements [`RawMutex`].
19///
20/// The [`MakeWriter::make_writer_for`] method takes [`Metadata`] describing a
21/// span or event and returns a writer. `MakeWriter`s can optionally provide
22/// implementations of this method with behaviors that differ based on the span
23/// or event being written. For example, events at different [levels] might be
24/// written to different output streams, or data from different [targets] might
25/// be written to separate log files. When the `MakeWriter` has no custom
26/// behavior based on metadata, the default implementation of `make_writer_for`
27/// simply calls `self.make_writer()`, ignoring the metadata. Therefore, when
28/// metadata _is_ available, callers should prefer to call `make_writer_for`,
29/// passing in that metadata, so that the `MakeWriter` implementation can choose
30/// the appropriate behavior.
31///
32/// [`fmt::Write`]: mycelium_util::fmt::Write
33/// [`Event`]: tracing_core::event::Event
34/// [`MakeWriter::make_writer_for`]: MakeWriter::make_writer_for
35/// [`Metadata`]: tracing_core::Metadata
36/// [levels]: tracing_core::Level
37/// [targets]: tracing_core::Metadata::target
38pub trait MakeWriter<'a> {
39    /// The concrete [`fmt::Write`] implementation returned by [`make_writer`].
40    ///
41    /// [`fmt::Write`]: mycelium_util::fmt::Write
42    /// [`make_writer`]: MakeWriter::make_writer
43    type Writer: fmt::Write;
44
45    /// Returns an instance of [`Writer`].
46    ///
47    /// # Implementer notes
48    ///
49    /// A [`Subscriber`] will call this method each  time an event is recorded.
50    /// Ensure any state that must be saved across writes is not lost when the
51    /// [`Writer`] instance is dropped. If creating a [`fmt::Write`] instance is
52    /// expensive, be sure to cache it when implementing [`MakeWriter`] to
53    /// improve performance.
54    ///
55    /// [`Writer`]: MakeWriter::Writer
56    /// [`Subscriber`]: crate::Subscriber
57    /// [`fmt::Write`]: mycelium_util::fmt::Write
58    fn make_writer(&'a self) -> Self::Writer;
59
60    fn enabled(&self, meta: &Metadata<'_>) -> bool {
61        let _ = meta;
62        true
63    }
64
65    /// Returns a [`Writer`] for writing data from the span or event described
66    /// by the provided [`Metadata`].
67    ///
68    /// By default, this calls [`self.make_writer()`][make_writer], ignoring
69    /// the provided metadata, but implementations can override this to provide
70    /// metadata-specific behaviors.
71    ///
72    /// This method allows `MakeWriter` implementations to implement different
73    /// behaviors based on the span or event being written. The `MakeWriter`
74    /// type might return different writers based on the provided metadata, or
75    /// might write some values to the writer before or after providing it to
76    /// the caller.
77    ///
78    /// [`Writer`]: MakeWriter::Writer
79    /// [`Metadata`]: tracing_core::Metadata
80    /// [make_writer]: MakeWriter::make_writer
81    /// [`WARN`]: tracing_core::Level::WARN
82    /// [`ERROR`]: tracing_core::Level::ERROR
83    #[inline]
84    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Option<Self::Writer> {
85        if self.enabled(meta) {
86            return Some(self.make_writer());
87        }
88
89        None
90    }
91
92    fn line_len(&self) -> usize {
93        80
94    }
95}
96
97/// Extension trait adding combinators for working with types implementing
98/// [`MakeWriter`].
99///
100/// This is not intended to be implemented directly for user-defined
101/// [`MakeWriter`]s; instead, it should be imported when the desired methods are
102/// used.
103pub trait MakeWriterExt<'a>: MakeWriter<'a> {
104    /// Wraps `self` and returns a [`MakeWriter`] that will only write output
105    /// for events at or below the provided verbosity [`Level`]. For instance,
106    /// `Level::TRACE` is considered to be _more verbose` than `Level::INFO`.
107    ///
108    /// Events whose level is more verbose than `level` will be ignored, and no
109    /// output will be written.
110    ///
111    /// [`Level`]: tracing_core::Level
112    /// [`fmt::Write`]: mycelium_util::fmt::Write
113    fn with_max_level(self, level: tracing_core::Level) -> WithMaxLevel<Self>
114    where
115        Self: Sized,
116    {
117        WithMaxLevel::new(self, level)
118    }
119
120    /// Wraps `self` and returns a [`MakeWriter`] that will only write output
121    /// for events at or above the provided verbosity [`Level`].
122    ///
123    /// Events whose level is less verbose than `level` will be ignored, and no
124    /// output will be written.
125    ///
126    /// [`Level`]: tracing_core::Level
127    /// [`fmt::Write`]: mycelium_util::fmt::Write
128    fn with_min_level(self, level: tracing_core::Level) -> WithMinLevel<Self>
129    where
130        Self: Sized,
131    {
132        WithMinLevel::new(self, level)
133    }
134
135    /// Wraps `self` with a predicate that takes a span or event's [`Metadata`]
136    /// and returns a `bool`. The returned [`MakeWriter`]'s
137    /// [`MakeWriter::make_writer_for`] method will check the predicate to
138    /// determine if  a writer should be produced for a given span or event.
139    ///
140    /// If the predicate returns `false`, the wrapped [`MakeWriter`]'s
141    /// [`make_writer_for`][mwf] will return [`None`].
142    /// Otherwise, it calls the wrapped [`MakeWriter`]'s
143    /// [`make_writer_for`][mwf] method, and returns the produced writer.
144    ///
145    /// This can be used to filter an output based on arbitrary [`Metadata`]
146    /// parameters.
147    ///
148    /// [`Metadata`]: tracing_core::Metadata
149    /// [mwf]: MakeWriter::make_writer_for
150    fn with_filter<F>(self, filter: F) -> WithFilter<Self, F>
151    where
152        Self: Sized,
153        F: Fn(&Metadata<'_>) -> bool,
154    {
155        WithFilter::new(self, filter)
156    }
157
158    /// Combines `self` with another type implementing [`MakeWriter`], returning
159    /// a new [`MakeWriter`] that produces [writers] that write to *both*
160    /// outputs.
161    ///
162    /// If writing to either writer returns an error, the returned writer will
163    /// return that error. However, both writers will still be written to before
164    /// the error is returned, so it is possible for one writer to fail while
165    /// the other is written to successfully.
166    ///
167    /// [writers]: mycelium_util::fmt::Write
168    fn and<B>(self, other: B) -> Tee<Self, B>
169    where
170        Self: Sized,
171        B: MakeWriter<'a> + Sized,
172    {
173        Tee::new(self, other)
174    }
175
176    /// Combines `self` with another type implementing [`MakeWriter`], returning
177    /// a new [`MakeWriter`] that calls `other`'s [`make_writer`] if `self`'s
178    /// `make_writer` returns [`None`].
179    ///
180    /// [`make_writer`]: MakeWriter::make_writer
181    fn or_else<B>(self, other: B) -> OrElse<Self, B>
182    where
183        Self: MakeWriter<'a> + Sized,
184        B: MakeWriter<'a> + Sized,
185    {
186        OrElse::new(self, other)
187    }
188
189    fn with_line_len(self, len: usize) -> WithLineLen<Self>
190    where
191        Self: MakeWriter<'a> + Sized,
192    {
193        WithLineLen::new(self, len)
194    }
195}
196
197/// A type implementing [`fmt::Write`] for a [`MutexGuard`] where the type
198/// inside the [`Mutex`] implements [`fmt::Write`].
199///
200/// This is used by the [`MakeWriter`] implementation for [`Mutex`], because
201/// [`MutexGuard`] itself will not implement [`fmt::Write`] — instead, it
202/// _dereferences_ to a type implementing [`fmt::Write`]. Because [`MakeWriter`]
203/// requires the `Writer` type to implement [`fmt::Write`], it's necessary to add
204/// a newtype that forwards the trait implementation.
205///
206/// [`fmt::Write`]: mycelium_util::fmt::Write
207/// [`MutexGuard`]: maitake::sync::blocking::MutexGuard
208/// [`Mutex`]: maitake::sync::blocking::Mutex
209/// [`MakeWriter`]: trait.MakeWriter.html
210#[derive(Debug)]
211pub struct MutexGuardWriter<'a, W, Lock: RawMutex = Spinlock>(MutexGuard<'a, W, Lock>);
212
213// TODO(eliza): put this back if needed
214/*
215/// A writer that erases the specific [`fmt::Write`] and [`MakeWriter`] types being used.
216///
217/// This is useful in cases where the concrete type of the writer cannot be known
218/// until runtime.
219///
220/// # Examples
221///
222/// A function that returns a [`Collect`] that will write to either stdout or stderr:
223///
224/// ```rust
225/// # use tracing::Collect;
226/// # use tracing_subscriber::fmt::writer::BoxMakeWriter;
227///
228/// fn dynamic_writer(use_stderr: bool) -> impl Collect {
229///     let writer = if use_stderr {
230///         BoxMakeWriter::new(core::io::stderr)
231///     } else {
232///         BoxMakeWriter::new(core::io::stdout)
233///     };
234///
235///     tracing_subscriber::fmt().with_writer(writer).finish()
236/// }
237/// ```
238///
239/// [`Collect`]: tracing::Collect
240/// [`fmt::Write`]: mycelium_util::fmt::Write
241pub struct BoxMakeWriter {
242    inner: Box<dyn for<'a> MakeWriter<'a, Writer = Box<dyn Write + 'a>> + Send + Sync>,
243    name: &'static str,
244}
245 */
246
247/// A [writer] that is one of two types implementing [`fmt::Write`].
248///
249/// This may be used by [`MakeWriter`] implementations that may conditionally
250/// return one of two writers.
251///
252/// [writer]: mycelium_util::fmt::Write
253#[derive(Copy, Clone, Debug, Eq, PartialEq)]
254pub enum EitherWriter<A, B> {
255    /// A writer of type `A`.
256    A(A),
257    /// A writer of type `B`.
258    B(B),
259}
260
261/// A [`MakeWriter`] combinator that only returns an enabled [writer] for spans
262/// and events with metadata at or below a specified verbosity [`Level`].
263///
264/// This is returned by the [`MakeWriterExt::with_max_level] method. See the
265/// method documentation for details.
266///
267/// [writer]: mycelium_util::fmt::Write
268/// [`Level`]: tracing_core::Level
269#[derive(Copy, Clone, Debug, Eq, PartialEq)]
270pub struct WithMaxLevel<M> {
271    make: M,
272    level: tracing_core::Level,
273}
274
275/// A [`MakeWriter`] combinator that only returns an enabled [writer] for spans
276/// and events with metadata at or above a specified verbosity [`Level`].
277///
278/// This is returned by the [`MakeWriterExt::with_min_level] method. See the
279/// method documentation for details.
280///
281/// [writer]: mycelium_util::fmt::Write
282/// [`Level`]: tracing_core::Level
283#[derive(Copy, Clone, Debug, Eq, PartialEq)]
284pub struct WithMinLevel<M> {
285    make: M,
286    level: tracing_core::Level,
287}
288
289/// A [`MakeWriter`] combinator that wraps a [`MakeWriter`] with a predicate for
290/// span and event [`Metadata`], so that the [`MakeWriter::make_writer_for`]
291/// method returns [`Some`] when the predicate returns `true`,
292/// and [`None`] when the predicate returns `false`.
293///
294/// This is returned by the [`MakeWriterExt::with_filter`] method. See the
295/// method documentation for details.
296///
297/// [`Metadata`]: tracing_core::Metadata
298#[derive(Copy, Clone, Debug, Eq, PartialEq)]
299pub struct WithFilter<M, F> {
300    make: M,
301    filter: F,
302}
303
304/// Combines a [`MakeWriter`] that returns an [`Option`] of another
305/// [`MakeWriter`], so that the second [`MakeWriter`] is used when the first
306/// [`MakeWriter`] returns [`None`].
307///
308/// This is returned by the [`MakeWriterExt::or_else] method. See the
309/// method documentation for details.
310#[derive(Copy, Clone, Debug, Eq, PartialEq)]
311pub struct OrElse<A, B> {
312    inner: A,
313    or_else: B,
314}
315
316/// Combines two types implementing [`MakeWriter`] (or [`mycelium_util::fmt::Write`]) to
317/// produce a writer that writes to both [`MakeWriter`]'s returned writers.
318///
319/// This is returned by the [`MakeWriterExt::and`] method. See the method
320/// documentation for details.
321#[derive(Copy, Clone, Debug, Eq, PartialEq)]
322pub struct Tee<A, B> {
323    a: A,
324    b: B,
325}
326
327#[derive(Copy, Clone, Debug, Eq, PartialEq)]
328pub struct WithLineLen<W> {
329    make: W,
330    len: usize,
331}
332
333#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
334pub struct NoWriter(());
335
336pub const fn none() -> NoWriter {
337    NoWriter(())
338}
339
340impl<'a, F, W> MakeWriter<'a> for F
341where
342    F: Fn() -> W,
343    W: fmt::Write,
344{
345    type Writer = W;
346
347    fn make_writer(&'a self) -> Self::Writer {
348        (self)()
349    }
350}
351
352impl<'a, M> MakeWriter<'a> for Option<M>
353where
354    M: MakeWriter<'a>,
355{
356    type Writer = EitherWriter<M::Writer, NoWriter>;
357    #[inline]
358    fn make_writer(&'a self) -> Self::Writer {
359        self.as_ref()
360            .map(MakeWriter::make_writer)
361            .map(EitherWriter::A)
362            .unwrap_or(EitherWriter::B(NoWriter(())))
363    }
364
365    #[inline]
366    fn enabled(&self, meta: &Metadata<'_>) -> bool {
367        self.as_ref()
368            .map(|make| make.enabled(meta))
369            .unwrap_or(false)
370    }
371
372    #[inline]
373    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Option<Self::Writer> {
374        self.as_ref()
375            .and_then(|make| make.make_writer_for(meta))
376            .map(EitherWriter::A)
377    }
378
379    #[inline]
380    fn line_len(&self) -> usize {
381        self.as_ref().map(MakeWriter::line_len).unwrap_or(80)
382    }
383}
384
385// === impl Mutex/MutexGuardWriter ===
386
387impl<'a, W, Lock> MakeWriter<'a> for Mutex<W, Lock>
388where
389    W: fmt::Write + 'a,
390    Lock: RawMutex + 'a,
391{
392    type Writer = MutexGuardWriter<'a, W, Lock>;
393
394    fn make_writer(&'a self) -> Self::Writer {
395        MutexGuardWriter(self.lock())
396    }
397}
398
399impl<W, Lock> fmt::Write for MutexGuardWriter<'_, W, Lock>
400where
401    W: fmt::Write,
402    Lock: RawMutex,
403{
404    #[inline]
405    fn write_str(&mut self, s: &str) -> fmt::Result {
406        self.0.write_str(s)
407    }
408
409    #[inline]
410    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> fmt::Result {
411        self.0.write_fmt(fmt)
412    }
413}
414
415// === impl EitherWriter ===
416
417impl<A, B> fmt::Write for EitherWriter<A, B>
418where
419    A: fmt::Write,
420    B: fmt::Write,
421{
422    #[inline]
423    fn write_str(&mut self, s: &str) -> fmt::Result {
424        match self {
425            EitherWriter::A(a) => a.write_str(s),
426            EitherWriter::B(b) => b.write_str(s),
427        }
428    }
429
430    #[inline]
431    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> fmt::Result {
432        match self {
433            EitherWriter::A(a) => a.write_fmt(fmt),
434            EitherWriter::B(b) => b.write_fmt(fmt),
435        }
436    }
437}
438
439impl<A, B> SetColor for EitherWriter<A, B>
440where
441    A: fmt::Write + SetColor,
442    B: fmt::Write + SetColor,
443{
444    fn set_fg_color(&mut self, color: Color) {
445        match self {
446            EitherWriter::A(a) => a.set_fg_color(color),
447            EitherWriter::B(b) => b.set_fg_color(color),
448        }
449    }
450
451    fn fg_color(&self) -> Color {
452        match self {
453            EitherWriter::A(a) => a.fg_color(),
454            EitherWriter::B(b) => b.fg_color(),
455        }
456    }
457
458    fn set_bold(&mut self, bold: bool) {
459        match self {
460            EitherWriter::A(a) => a.set_bold(bold),
461            EitherWriter::B(b) => b.set_bold(bold),
462        }
463    }
464}
465
466// === impl WithMaxLevel ===
467
468impl<M> WithMaxLevel<M> {
469    /// Wraps the provided [`MakeWriter`] with a maximum [`Level`], so that it
470    /// returns [`None`] for spans and events whose level is
471    /// more verbose than the maximum level.
472    ///
473    /// See [`MakeWriterExt::with_max_level`] for details.
474    ///
475    /// [`Level`]: tracing_core::Level
476    pub fn new(make: M, level: tracing_core::Level) -> Self {
477        Self { make, level }
478    }
479}
480
481impl<'a, M: MakeWriter<'a>> MakeWriter<'a> for WithMaxLevel<M> {
482    type Writer = M::Writer;
483
484    #[inline(always)]
485    fn make_writer(&'a self) -> Self::Writer {
486        self.make.make_writer()
487    }
488
489    #[inline(always)]
490    fn enabled(&self, meta: &Metadata<'_>) -> bool {
491        meta.level() <= &self.level && self.make.enabled(meta)
492    }
493
494    #[inline(always)]
495    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Option<Self::Writer> {
496        if self.enabled(meta) {
497            return self.make.make_writer_for(meta);
498        }
499
500        None
501    }
502
503    #[inline(always)]
504    fn line_len(&self) -> usize {
505        self.make.line_len()
506    }
507}
508
509// === impl WithMinLevel ===
510
511impl<M> WithMinLevel<M> {
512    /// Wraps the provided [`MakeWriter`] with a minimum [`Level`], so that it
513    /// returns [`None`] for spans and events whose level is
514    /// less verbose than the maximum level.
515    ///
516    /// See [`MakeWriterExt::with_min_level`] for details.
517    ///
518    /// [`Level`]: tracing_core::Level
519    pub fn new(make: M, level: tracing_core::Level) -> Self {
520        Self { make, level }
521    }
522}
523
524impl<'a, M: MakeWriter<'a>> MakeWriter<'a> for WithMinLevel<M> {
525    type Writer = M::Writer;
526
527    #[inline]
528    fn make_writer(&'a self) -> Self::Writer {
529        self.make.make_writer()
530    }
531
532    fn enabled(&self, meta: &Metadata<'_>) -> bool {
533        meta.level() >= &self.level && self.make.enabled(meta)
534    }
535
536    #[inline]
537    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Option<Self::Writer> {
538        if self.enabled(meta) {
539            return self.make.make_writer_for(meta);
540        }
541
542        None
543    }
544
545    #[inline]
546    fn line_len(&self) -> usize {
547        self.make.line_len()
548    }
549}
550
551// ==== impl WithFilter ===
552
553impl<M, F> WithFilter<M, F> {
554    /// Wraps `make` with the provided `filter`, returning a [`MakeWriter`] that
555    /// will call `make.make_writer_for()` when `filter` returns `true` for a
556    /// span or event's [`Metadata`], and returns [`None`] otherwise.
557    ///
558    /// See [`MakeWriterExt::with_filter`] for details.
559    ///
560    /// [`Metadata`]: tracing_core::Metadata
561    pub fn new(make: M, filter: F) -> Self
562    where
563        F: Fn(&Metadata<'_>) -> bool,
564    {
565        Self { make, filter }
566    }
567}
568
569impl<'a, M, F> MakeWriter<'a> for WithFilter<M, F>
570where
571    M: MakeWriter<'a>,
572    F: Fn(&Metadata<'_>) -> bool,
573{
574    type Writer = M::Writer;
575
576    #[inline]
577    fn make_writer(&'a self) -> Self::Writer {
578        self.make.make_writer()
579    }
580
581    #[inline]
582    fn enabled(&self, meta: &Metadata<'_>) -> bool {
583        (self.filter)(meta) && self.make.enabled(meta)
584    }
585
586    #[inline]
587    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Option<Self::Writer> {
588        if self.enabled(meta) {
589            return self.make.make_writer_for(meta);
590        }
591
592        None
593    }
594
595    #[inline]
596    fn line_len(&self) -> usize {
597        self.make.line_len()
598    }
599}
600
601// === impl Tee ===
602
603impl<A, B> Tee<A, B> {
604    /// Combines two types implementing [`MakeWriter`], returning
605    /// a new [`MakeWriter`] that produces [writers] that write to *both*
606    /// outputs.
607    ///
608    /// See the documentation for [`MakeWriterExt::and`] for details.
609    ///
610    /// [writers]: fmt::Write
611    pub fn new(a: A, b: B) -> Self {
612        Self { a, b }
613    }
614}
615
616// impl<'a, A, B> MakeWriter<'a> for Tee<A, B>
617// where
618//     A: MakeWriter<'a>,
619//     B: MakeWriter<'a>,
620// {
621//     type Writer = Tee<A::Writer, B::Writer>;
622
623//     #[inline]
624//     fn make_writer(&'a self) -> Self::Writer {
625//         Tee::new(self.a.make_writer(), self.b.make_writer())
626//     }
627
628//     #[inline]
629//     fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Self::Writer {
630//         Tee::new(self.a.make_writer_for(meta), self.b.make_writer_for(meta))
631//     }
632// }
633
634// macro_rules! impl_tee {
635//     ($self_:ident.$f:ident($($arg:ident),*)) => {
636//         {
637//             let res_a = $self_.a.$f($($arg),*);
638//             let res_b = $self_.b.$f($($arg),*);
639//             (res_a?, res_b?)
640//         }
641//     }
642// }
643
644// impl<A, B> fmt::Write for Tee<A, B>
645// where
646//     A: fmt::Write,
647//     B: fmt::Write,
648// {
649//     #[inline]
650//     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
651//         let (a, b) = impl_tee!(self.write(buf));
652//         Ok(core::cmp::max(a, b))
653//     }
654
655//     #[inline]
656//     fn flush(&mut self) -> io::Result<()> {
657//         impl_tee!(self.flush());
658//         Ok(())
659//     }
660
661//     #[inline]
662//     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
663//         impl_tee!(self.write_all(buf));
664//         Ok(())
665//     }
666
667//     #[inline]
668//     fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
669//         impl_tee!(self.write_fmt(fmt));
670//         Ok(())
671//     }
672// }
673
674// === impl OrElse ===
675
676impl<A, B> OrElse<A, B> {
677    /// Combines
678    pub fn new<'a>(inner: A, or_else: B) -> Self
679    where
680        A: MakeWriter<'a>,
681        B: MakeWriter<'a>,
682    {
683        Self { inner, or_else }
684    }
685}
686
687impl<'a, A, B> MakeWriter<'a> for OrElse<A, B>
688where
689    A: MakeWriter<'a>,
690    B: MakeWriter<'a>,
691{
692    type Writer = EitherWriter<A::Writer, B::Writer>;
693
694    #[inline]
695    fn make_writer(&'a self) -> Self::Writer {
696        EitherWriter::A(self.inner.make_writer())
697    }
698
699    #[inline]
700    fn enabled(&self, meta: &Metadata<'_>) -> bool {
701        self.inner.enabled(meta) || self.or_else.enabled(meta)
702    }
703
704    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Option<Self::Writer> {
705        self.inner
706            .make_writer_for(meta)
707            .map(EitherWriter::A)
708            .or_else(|| self.or_else.make_writer_for(meta).map(EitherWriter::B))
709    }
710
711    #[inline]
712    fn line_len(&self) -> usize {
713        core::cmp::min(self.inner.line_len(), self.or_else.line_len())
714    }
715}
716
717// === impl WithLineLen ===
718
719impl<W> WithLineLen<W> {
720    /// Combines
721    pub fn new(make: W, len: usize) -> Self {
722        Self { make, len }
723    }
724}
725
726impl<'a, W> MakeWriter<'a> for WithLineLen<W>
727where
728    W: MakeWriter<'a>,
729{
730    type Writer = W::Writer;
731
732    #[inline]
733    fn make_writer(&'a self) -> Self::Writer {
734        self.make.make_writer()
735    }
736
737    #[inline]
738    fn enabled(&self, meta: &Metadata<'_>) -> bool {
739        self.make.enabled(meta)
740    }
741
742    #[inline]
743    fn make_writer_for(&'a self, meta: &Metadata<'_>) -> Option<Self::Writer> {
744        self.make.make_writer_for(meta)
745    }
746
747    #[inline]
748    fn line_len(&self) -> usize {
749        self.len
750    }
751}
752
753// === impl NoWriter ===
754
755impl fmt::Write for NoWriter {
756    #[inline]
757    fn write_str(&mut self, _: &str) -> fmt::Result {
758        Ok(())
759    }
760
761    #[inline]
762    fn write_fmt(&mut self, _: fmt::Arguments<'_>) -> fmt::Result {
763        Ok(())
764    }
765}
766
767impl<'a> MakeWriter<'a> for NoWriter {
768    type Writer = Self;
769
770    #[inline]
771    fn make_writer(&'a self) -> Self::Writer {
772        Self(())
773    }
774
775    #[inline]
776    fn enabled(&self, _: &Metadata<'_>) -> bool {
777        false
778    }
779
780    #[inline]
781    fn make_writer_for(&'a self, _: &Metadata<'_>) -> Option<Self::Writer> {
782        None
783    }
784}
785
786impl SetColor for NoWriter {
787    fn set_fg_color(&mut self, _: Color) {
788        // nop
789    }
790
791    fn fg_color(&self) -> Color {
792        Color::Default
793    }
794
795    fn set_bold(&mut self, _: bool) {
796        // nop
797    }
798}
799
800// === blanket impls ===
801
802impl<'a, M> MakeWriterExt<'a> for M where M: MakeWriter<'a> {}